IP address structure of network equipment
Reply to the IP address structure of the network device ==================== (1) In the TCPIP protocol environment, the network device structure (NET_DEVICE) has an IP_PTR pointer to the IP protocol. Equipment parameter block (in_Device), which contains the device IP address structure (IFA_LIST) of the device IP address structure (IFA_LIST) .IP address structure chain can configure multiple IP addresses for a network device, so that the single host in the LAN can simulate multiple hosts The role. (2) The configuration of the device IP address is complete by the application using the IFREQ parameter structure via the IOCTL () system. The different IP addresses of the same device are identified by different device alias, such as "eth0: 1" and "eth0 : 2 "represents two addresses of the device EHT0. When an individual name is added, if its address is the same subnet, its address is marked as" dependent "(IFA_F_Secondary). When the alignment is deleted, the IP parameter block of the device will be released. When the device address parameter changes, the notification message will be sent to the relevant subsystem through the address message chain (inetaddr_chain), for example, the routing subsystem is used to refresh the forward table and the routing buffer table. .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; device address u32 ifa_address; Total-to-end address U32 IFA_MASK; network address mask U32 IFA_Broadcast; device broadcast address u32 IFA_AN ycast; unsigned char ifa_scope; addressing range of the device address unsigned char ifa_flags; address mark unsigned char ifa_prefixlen; device network address length char ifa_label [IFNAMSIZ]; device IP address tag}; / * * 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, eg "en0 "* /} IFR_IFRN; UNION {STRUCKADDR IFRU_ADDR; STRUCT SOCKADDR IFRU_DSTADDR; STRUCT SOCKADDR IFRU_BROADDR; 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, ':'); Take the device name IF (color) * colon = 0 from the device address tag; #ifdef config_kmod dev_load (ifr.ifr_name ); loading the appropriate device driver module name #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 shock here (i mean SMP) * / MEMSET (SIN, 0, SIZEOF (* sin)); sin-> sin_family = AF_INET; break; case SIOCSIFFLAGS: if) return -EACCES; break; case SIOCSIFADDR (capable (CAP_NET_ADMIN!): / * 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 return -EACCES; if (sin-> sin_family (capable (CAP_NET_ADMIN)!)! = AF_INET) RETURN-EINVAL; Break; Default: return-Einval;
} DEV_PROBE_LOCK (); RTNL_LOCK (); if ((dev = __DEV_GET_BY_NAME (IFR.IFR_NAME)) == NULL) {Take the device structure RET = -enodev; goto done;} if (color) * colon = ':'; recovery User Address Tag IF ((IN_DEV = __ IN_DEV_GET)! = NULL) {Take IP Device Block For (ifap = & in_DEV-> IFA_List; (IFA = * IFAP)! = NULL; IFAP = & IFA-> IFA_NEXT) IF ( Strcmp (ifr.ifr_name, IFA-> IFA_Label) == 0) Break; Take the device address structure corresponding to the user address tag} IF (ifa == null && cmd! = siocaddr && cmd! = siocsifflags) {In addition to setting address and settings Sign RET = -EADDRNOTAVAIL; GOTO DONE;} Switch (cmd) {Case SiocGifaddr: / * get interface address * / sin-> sin_addr.s_addr = ifa-> ifa_local; Take the device IP address Goto Rarok; Case Siocgifbrdaddr: / * Get the broadcast address * / sin-> sin_addr.s_addr = ifa-> ifa_broadcast; IP broadcast address to take equipment goto rarok; case SIOCGIFDSTADDR: / * get the destination address * / sin-> sin_addr.s_addr = ifa-> ifa_address; take point Each of the device's peer IP address Goto Rarok; Case SiocgifNetmask: / * get the netmask for the interface * / sin-> sin_addr.s_addr = ifa-> ifa_mask; Take the IP address mask of the device Goto Rarok; Case SiocFlags: Setting the device flagIf (color) {if (ifa == null) {RET = -EADDRNOTAVAIL; BREAK;} if (! (ifr.ifr_flags & iff_up)) If the flag is turned off device INET_DEL_IFA (IN_DEV, IFAP, 1); breaking loop delete this address Structure Break;} RET = dev_change_flags (dev, ifr.ifr_flags); Break; Case SiocAddr: / * set interface address (and family) * / if (inet_abc_len (sin-> sin_addr.s_addr) <0) {Take Network Address Bit Long RET =-EinVal; Break;}} (!) {If the device has no address structure IF ((ifa = inet_alloc_ifa ()) == null) {Assign address structure RET = -Enobufs; Break;} if (colon) If the address label is the device alias tag Memcpy (ifa->
IFA_Label, IFR.IFR_NAME, IFNAMSIZ); Else Memcpy (IFA-> IFA_Label, DEV-> Name, IFNAMSIZ);} else {If the device address RET = 0; if (ifa-> ifa_local == sin-> sin_addr.s_addr Break; INET_DEL_IFA (IN_DEV, IFAP, 0); Remove the address structure from the link IFA-> IFA_Broadcast = 0; IFA-> IFA_Ancast = 0;} IFA-> IFA_Address = ifa-> ifa_local = sin-> sin_addr.s_addr Set the device address and the peer address to the new address IF (! (Dev-> flags & iff_pointopoint)) {If the non-point-to-peer device IFA-> IFA_PREFIXLEN = INET_ABC_LEN (ifa-> ifa_address); Take the address of the address length IFA-> IFA_MASK = INET_MAKE_MASK (IFA-> IFA_PREFIXLEN); ask for network mask if ((dev-> flags & imp_broadcast) && ifa-> ifa_prefixlen <31) IFA-> IFA_Broadcast = ifa-> ifa_address | ~ IFA-> IFA_MASK; Settings Standard Broadcast Address} ELSE {If it is a point-to-point device IFA-> ifa_prefixlen = 32; network address length is 32 IFA-> IFA_MASK = INET_MAKE_MASK (32);} RET = INET_SET_IFA (DEV, IFA); Add Device Address Break; Case Siocbsifbraddr: / * 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 intinet_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) {in_dev = inetdev_init (dev) if IP device block does not exist; distribution IP device block if (in_dev == null) {inet_free_ifa (IFA); return -Enobufs;}}}} (ifa-> ifa_dev! = In_dev) {bug_trap (ifa-> ifa_dev == null); in_DEV_HOLD (IN_DEV); IFA -> IFA_DEV = IN_DEV; Bind the address structure to the IP device block} if (loopback (ifa-> ifa_local)) If the device address is a return address IFA-> ifa_scope = rScope_host; address is the address of the host Return INET_INSERT_IFA (IFA);} static intinet_insert_ifa (struct in_ifaddr * ifa) {struct in_Device * in_dev = ifa-> ifa_dev; struct in_ifaddr * if A1, ** iFAP, ** last_primary; assert_rtnl (); if (IFA-> IFA_LOCAL == 0) {inet_free_ifa (IFA); Return 0;} IFA-> IFA_FLAGS & = ~ IFA_F_Secondary; Clear address structure Laborat Last_Primary = & in_DEV-> IFA_List; Take IP Device Block Address Links Pointer Address for (ifap = & in_DEV-> IFA_LIST; (IFA1 = * IFAP)! = NULL; ifap = & ifa1-> ifa_next) {Scan the address chain on the IP device block 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)) {; If an address in the chain has the same network address IF (IFA1->
IFA_LOCAL == IFA-> ifa_local) {If the address is the same INET_FREE_IFA (IFA); return -eexist;} if (ifa1-> ifa_scope! = ifa-> ifa_scope) {If the range of addresses INET_FREE_IFA (IFA); return -EINVAL;} ifa-> ifa_flags | = IFA_F_SECONDARY; labeled as slave address}} 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); distribution apparatus start message return 0;} static voidinet_del_ifa (struct in_device * in_dev, struct in_ifaddr ** ifap, int destroy) {struct in_ifaddr * ifa1 = * ifap; take to delete an address ASSERT_RTNL address structure (); / * 1. deleting primary ifaddr forces deletion all secondaries * / if {if deleted is the apparatus main address structure struct in_ifaddr * ifa ((ifa1-> ifa_flags & IFA_F_SECONDARY)!); struct in_ifaddr ** ifap1 = & i FA1-> ifa_next; Remove the address of an address pointer while ((ifa = * ifap1)! = null) {if (! (ifa-> ifa_flags & ifa_f_secondary) || If the primary address 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); equipment downtime release message inet_free_ifa (ifa);}} / * 2. Unlink it * / write_lock_bh (& in_dev-> lock); * ifap = ifa1-> ifa_next; from Delete this address tag 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 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) == 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 __inl ine__ struct in_device * __ in_dev_get (const struct net_device * dev) {return (struct in_device *) dev-> ip_ptr;} extern __inline__ voidin_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 / N ", IDEV, DEV? dev-> name:" nil "); # endif dev_put (dev); if (! IDEV-> dead) {printk (" Freeing Alive In_Device% P / N ", IDEV); Return;