如何将一个net_proto_family注册到相应的协议簇

我们先来看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))


 协议软件  协议类型 和协议号 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值