Chinaunix首页 | 论坛 | 博客
  • 博客访问: 82716
  • 博文数量: 36
  • 博客积分: 811
  • 博客等级: 军士长
  • 技术积分: 350
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-17 18:07
文章分类

全部博文(36)

文章存档

2013年(1)

2012年(25)

2011年(10)

我的朋友

分类: LINUX

2012-02-21 21:27:01

应用层通过pfkey, dump sa的方法:
创建pfkeyl类型的一个socket,
发送sendmsg,
然后通过while循环调用recvmsg

在kernel里对应的处理:


1. pfkey_sendmsg
内核使用xfrmwalk遍历存放SA的hash list。
将每个SA的信息转化为一个skb,
将这个skb添加到对应的pfkey socket的sk_receive_queue链表里。
遍历完成后,删除xfrmwalk。

每次添加Skb时候会检查是否超出socket允许接受的最大receive 字节数。

如果SA的数量比较多,无法一次将所有的SA信息转化为skb,
并保存的socket的receive队列里。
则将xfrmwalk暂时寄存到sa的hashlist里,等待socket的已接受的数据被
消耗掉一步部分后,再继续激活pfkey_do_dump。 

如果搜有的SA都全部dump完了则释放xfrmwalk。

 =====> err = pfkey_process(sk, skb, hdr);
 =====>  =====> err = pfkey_funcs[hdr->sadb_msg_type](sk, skb, hdr, ext_hdrs);
 =====>  =====>  =====> pfkey_dump
static pfkey_handler pfkey_funcs[SADB_MAX + 1] = {
[SADB_DUMP]             = pfkey_dump,

 =====>  =====>  =====>  =====> pfkey_do_dump
        pfk->dump.msg_pid = hdr->sadb_msg_pid;
        pfk->dump.dump = pfkey_dump_sa;
        pfk->dump.done = pfkey_dump_sa_done;
        xfrm_state_walk_init(&pfk->dump.u.state, proto);
        return pfkey_do_dump(pfk);
 =====>  =====>  =====>   =====>  =====> rc = pfk->dump.dump(pfk);
  1.  281 static int pfkey_do_dump(struct pfkey_sock *pfk)
  2.  282 {
  3.  283 struct sadb_msg *hdr;
  4.  284 int rc;
  5.  285
  6.  286 rc = pfk->dump.dump(pfk);
  7.  287 if (rc == -ENOBUFS)
  8.  288 return 0;
  9.  289
  10.  290 if (pfk->dump.skb) {
  11.  291 if (!pfkey_can_dump(&pfk->sk))
  12.  292 return 0;
  13.  293
  14.  294 hdr = (struct sadb_msg *) pfk->dump.skb->data;
  15.  295 hdr->sadb_msg_seq = 0;
  16.  296 hdr->sadb_msg_errno = rc;
  17.  297 pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
  18.  298 &pfk->sk, sock_net(&pfk->sk));
  19.  299 pfk->dump.skb = NULL;
  20.  300 }
  21.  301
  22.  302 pfkey_terminate_dump(pfk);
  23.  303 return rc;
  24.  304 }
 286 rc = pfk->dump.dump(pfk);
相当于pfkey_dump_sa

=====> 针对SA 每个sa调用
=====> =====>dump_sa
=====> =====> =====> pfkey_broadcast_one
=====> =====> =====> =====> skb_queue_tail(&sk->sk_receive_queue, *skb2);

  1. xfrm_state_walk(net, &pfk->dump.u.state, dump_sa, (void *) pfk);

  2. 1561 int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
  3. 1562 int (*func)(struct xfrm_state *, int, void*),
  4. 1563 void *data)
  5. 1564 {
  6. 1565 struct xfrm_state *state;
  7. 1566 struct xfrm_state_walk *x;
  8. 1567 int err = 0;
  9. 1568
  10. 1569 if (walk->seq != 0 && list_empty(&walk->all))
  11. 1570 return 0;
  12. 1571
  13. 1572 spin_lock_bh(&xfrm_state_lock);
  14. 1573 if (list_empty(&walk->all))
  15. 1574 x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all);
  16. 1575 else
  17. 1576 x = list_entry(&walk->all, struct xfrm_state_walk, all);
  18. 1577 list_for_each_entry_from(x, &net->xfrm.state_all, all) {
  19. 1578 if (x->state == XFRM_STATE_DEAD)
  20. 1579 continue;
  21. 1580 state = container_of(x, struct xfrm_state, km);
  22. 1581 if (!xfrm_id_proto_match(state->id.proto, walk->proto))
  23. 1582 continue;
  24. 1583 err = func(state, walk->seq, data);  <==== fun 相当于 dump_sa
  25. 1584 if (err) {
  26. 1585 list_move_tail(&walk->all, &x->all);
  27. 1586 goto out;
  28. 1587 }
  29. 1588 walk->seq++;
  30. 1589 }
  31. 1590 if (walk->seq == 0) {
  32. 1591 err = -ENOENT;
  33. 1592 goto out;
  34. 1593 }
  35. 1594 list_del_init(&walk->all);
  36. 1595 out:
  37. 1596 spin_unlock_bh(&xfrm_state_lock);
  38. 1597 return err;
  39. 1598 }
2. recvmsg
跟普通socket的recvmsg没有太大的区别。
调用skb_recv_datagram从socket的sk_receive_queue队列里摘一个skb下来,
并将skb的数据copy到用户空间。

检查SA是否已经全部dump了。
否则如果socket的有比较宽裕的剩余空间,则再次激活SA dump。
宽裕的剩余空间的检查,保证了dump的效率,
避免激活一次SA dump只能dump很少的SA。

  1. 3578 static int pfkey_recvmsg(struct kiocb *kiocb,
  2. 3579 struct socket *sock, struct msghdr *msg, size_t len,
  3. 3580 int flags)
  4. 3581 {
  5. 3582 struct sock *sk = sock->sk;
  6. 3583 struct pfkey_sock *pfk = pfkey_sk(sk);
  7. 3584 struct sk_buff *skb;
  8. 3585 int copied, err;
  9. 3586
  10. 3587 err = -EINVAL;
  11. 3588 if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT))
  12. 3589 goto out;
  13. 3590
  14. 3591 msg->msg_namelen = 0;
  15. 3592 skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err);
  16. 3593 if (skb == NULL)
  17. 3594 goto out;
  18. 3595
  19. 3596 copied = skb->len;
  20. 3597 if (copied > len) {
  21. 3598 msg->msg_flags |= MSG_TRUNC;
  22. 3599 copied = len;
  23. 3600 }
  24. 3601
  25. 3602 skb_reset_transport_header(skb);
  26. 3603 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
  27. 3604 if (err)
  28. 3605 goto out_free;
  29. 3606
  30. 3607 sock_recv_ts_and_drops(msg, sk, skb);
  31. 3608
  32. 3609 err = (flags & MSG_TRUNC) ? skb->len : copied;
  33. 3610
  34. 3611 if (pfk->dump.dump != NULL &&     <===检查SA是否dump完成
  35. 3612 3 * atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf)    <===检查是否有宽裕的剩余buff空间
  36. 3613 pfkey_do_dump(pfk);   <===满足条件,重新激活SA dump
  37. 3614。
  38. 3615 out_free:
  39. 3616 skb_free_datagram(sk, skb);
  40. 3617 out:
  41. 3618 return err;
  42. 3619 }
阅读(1404) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~