我们先来看sock_register的源码,也就是如何将一个net_proto_family注册到相应的数组:
static const struct net_proto_family *net_families[NPROTO] __read_mostly;
int sock_register(const struct net_proto_family *ops)
{
int err;
if (ops->family >= NPROTO) {
printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family,
NPROTO);
return -ENOBUFS;
}
spin_lock(&net_family_lock);
///代码非常简单,就是根据类型,然后放到相应的位置.
if (net_families[ops->family])
err = -EEXIST;
else {
net_families[ops->family] = ops;
err = 0;
}
spin_unlock(&net_family_lock);
printk(KERN_INFO "NET: Registered protocol family %d\n", ops->family);
return err;
}
static const struct net_proto_family *net_families[NPROTO] __read_mostly;
int sock_register(const struct net_proto_family *ops)
{
int err;
if (ops->family >= NPROTO) {
printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family,
NPROTO);
return -ENOBUFS;
}
spin_lock(&net_family_lock);
///代码非常简单,就是根据类型,然后放到相应的位置.
if (net_families[ops->family])
err = -EEXIST;
else {
net_families[ops->family] = ops;
err = 0;
}
spin_unlock(&net_family_lock);
printk(KERN_INFO "NET: Registered protocol family %d\n", ops->family);
return err;
}
struct net_proto_family {
int family;
int (*create)(struct socket *sock, int protocol);
struct module *owner;
};
每个网络协议簇有自己的create方法
有自己的协议簇号 实际上就是在数组中的下标
static const struct net_proto_family *net_families[NPROTO] __read_mostly;
我们知道每个协议簇和相应的套接口都对应有好多种组合,因此在协议簇的实现中保存了一个相应的结构来保存这些组合,然后后面就首先通过family然后确定到某个结构,
再根据套接口的类型来得到这个结构,并赋值给sock.
这里要注意我们只分析af_inet的实现,其他的协议簇都差不多:
我们来看这个的实现:
///可以看到这是一个数组,每个元素都是一个链表,也就是每种类型的socket就是一个链表.而这个链表所包含的是不同4层协议的inetsw.
可是在inet中,现在每种类型的socket只对应一个4层协议.这里只是为了以后扩展.
static struct list_head inetsw[SOCK_MAX];
static DEFINE_SPINLOCK(inetsw_lock);
///相应的socket的对应的信息的结构.
struct inet_protosw {
struct list_head list;
///需要这两个key才能定位一个inet_protosw.
unsigned short type; /* This is the 2nd argument to socket(2). */
unsigned short protocol; /* This is the L4 protocol number. */
///相应的基于ipv4的4层协议的操作集合.
struct proto *prot;
///相应的协议簇的操作信息.
const struct proto_ops *ops;
int capability; /* Which (if any) capability do
* we need to use this socket
* interface?
*/
char no_check; /* checksum on rcv/xmit/none? */
unsigned char flags; /* See INET_PROTOSW_* below. */
};
void inet_register_protosw(struct inet_protosw *p)
{
struct list_head *lh;
struct inet_protosw *answer;
int protocol = p->protocol;
struct list_head *last_perm;
.............................................
answer = NULL;
last_perm = &inetsw[p->type];
///这个操作也很简单,就是将inet_protosw根据套接口类型插入到全局链表数组.
list_for_each(lh, &inetsw[p->type]) {
answer = list_entry(lh, struct inet_protosw, list);
/* Check only the non-wild match. */
if (INET_PROTOSW_PERMANENT & answer->flags) {
if (protocol == answer->protocol)
break;
last_perm = lh;
}
answer = NULL;
}
if (answer)
goto out_permanent;
///插入链表.
list_add_rcu(&p->list, last_perm);
..............................
///可以看到这是一个数组,每个元素都是一个链表,也就是每种类型的socket就是一个链表.而这个链表所包含的是不同4层协议的inetsw.可是在inet中,现在每种类型的socket只对应一个4层协议.这里只是为了以后扩展.
static struct list_head inetsw[SOCK_MAX];
///相应的socket的对应的信息的结构.
struct inet_protosw {
struct list_head list;
///需要这两个key才能定位一个inet_protosw.
unsigned short type; /* This is the 2nd argument to socket(2). */
unsigned short protocol; /* This is the L4 protocol number. */
///相应的基于ipv4的4层协议的操作集合.
struct proto *prot;
///相应的协议簇的操作信息.
const struct proto_ops *ops;
int capability; /* Which (if any) capability do
* we need to use this socket
* interface?
*/
char no_check; /* checksum on rcv/xmit/none? */
unsigned char flags; /* See INET_PROTOSW_* below. */
};
void inet_register_protosw(struct inet_protosw *p)
{
struct list_head *lh;
struct inet_protosw *answer;
int protocol = p->protocol;
struct list_head *last_perm;
.............................................
answer = NULL;
last_perm = &inetsw[p->type];
///这个操作也很简单,就是将inet_protosw根据套接口类型插入到全局链表数组.
list_for_each(lh, &inetsw[p->type]) {
answer = list_entry(lh, struct inet_protosw, list);
/* Check only the non-wild match. */
if (INET_PROTOSW_PERMANENT & answer->flags) {
if (protocol == answer->protocol)
break;
last_perm = lh;
}
answer = NULL;
}
if (answer)
goto out_permanent;
///插入链表.
list_add_rcu(&p->list, last_perm);
..............................
/* Upon startup we insert all the elements in inetsw_array[] into
* the linked list inetsw.
*/
static struct inet_protosw inetsw_array[] =
{
{
.type = SOCK_STREAM,
.protocol = IPPROTO_TCP,
.prot = &tcp_prot,
.ops = &inet_stream_ops,
.capability = -1,
.no_check = 0,
.flags = INET_PROTOSW_PERMANENT |
INET_PROTOSW_ICSK,
},
{
.type = SOCK_DGRAM,
.protocol = IPPROTO_UDP,
.prot = &udp_prot,
.ops = &inet_dgram_ops,
.capability = -1,
.no_check = UDP_CSUM_DEFAULT,
.flags = INET_PROTOSW_PERMANENT,
},
{
.type = SOCK_RAW,
.protocol = IPPROTO_IP, /* wild card */
.prot = &raw_prot,
.ops = &inet_sockraw_ops,
.capability = CAP_NET_RAW,
.no_check = UDP_CSUM_DEFAULT,
.flags = INET_PROTOSW_REUSE,
}
};
#define INETSW_ARRAY_LEN (sizeof(inetsw_array) / sizeof(struct inet_protosw))
协议软件 协议类型 和协议号