应用层通过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);
- 281 static int pfkey_do_dump(struct pfkey_sock *pfk)
-
282 {
-
283 struct sadb_msg *hdr;
-
284 int rc;
-
285
-
286 rc = pfk->dump.dump(pfk);
-
287 if (rc == -ENOBUFS)
-
288 return 0;
-
289
-
290 if (pfk->dump.skb) {
-
291 if (!pfkey_can_dump(&pfk->sk))
-
292 return 0;
-
293
-
294 hdr = (struct sadb_msg *) pfk->dump.skb->data;
-
295 hdr->sadb_msg_seq = 0;
-
296 hdr->sadb_msg_errno = rc;
-
297 pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
-
298 &pfk->sk, sock_net(&pfk->sk));
-
299 pfk->dump.skb = NULL;
-
300 }
-
301
-
302 pfkey_terminate_dump(pfk);
-
303 return rc;
-
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);
- xfrm_state_walk(net, &pfk->dump.u.state, dump_sa, (void *) pfk);
-
-
1561 int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
-
1562 int (*func)(struct xfrm_state *, int, void*),
-
1563 void *data)
-
1564 {
-
1565 struct xfrm_state *state;
-
1566 struct xfrm_state_walk *x;
-
1567 int err = 0;
-
1568
-
1569 if (walk->seq != 0 && list_empty(&walk->all))
-
1570 return 0;
-
1571
-
1572 spin_lock_bh(&xfrm_state_lock);
-
1573 if (list_empty(&walk->all))
-
1574 x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all);
-
1575 else
-
1576 x = list_entry(&walk->all, struct xfrm_state_walk, all);
-
1577 list_for_each_entry_from(x, &net->xfrm.state_all, all) {
-
1578 if (x->state == XFRM_STATE_DEAD)
-
1579 continue;
-
1580 state = container_of(x, struct xfrm_state, km);
-
1581 if (!xfrm_id_proto_match(state->id.proto, walk->proto))
-
1582 continue;
-
1583 err = func(state, walk->seq, data); <==== fun 相当于
dump_sa
-
1584 if (err) {
-
1585 list_move_tail(&walk->all, &x->all);
-
1586 goto out;
-
1587 }
-
1588 walk->seq++;
-
1589 }
-
1590 if (walk->seq == 0) {
-
1591 err = -ENOENT;
-
1592 goto out;
-
1593 }
-
1594 list_del_init(&walk->all);
-
1595 out:
-
1596 spin_unlock_bh(&xfrm_state_lock);
-
1597 return err;
-
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。
- 3578 static int pfkey_recvmsg(struct kiocb *kiocb,
-
3579 struct socket *sock, struct msghdr *msg, size_t len,
-
3580 int flags)
-
3581 {
-
3582 struct sock *sk = sock->sk;
-
3583 struct pfkey_sock *pfk = pfkey_sk(sk);
-
3584 struct sk_buff *skb;
-
3585 int copied, err;
-
3586
-
3587 err = -EINVAL;
-
3588 if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT))
-
3589 goto out;
-
3590
-
3591 msg->msg_namelen = 0;
-
3592 skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err);
-
3593 if (skb == NULL)
-
3594 goto out;
-
3595
-
3596 copied = skb->len;
-
3597 if (copied > len) {
-
3598 msg->msg_flags |= MSG_TRUNC;
-
3599 copied = len;
-
3600 }
-
3601
-
3602 skb_reset_transport_header(skb);
-
3603 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
-
3604 if (err)
-
3605 goto out_free;
-
3606
-
3607 sock_recv_ts_and_drops(msg, sk, skb);
-
3608
-
3609 err = (flags & MSG_TRUNC) ? skb->len : copied;
-
3610
-
3611 if (pfk->dump.dump != NULL &&
<===检查SA是否dump完成
-
3612 3 * atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf)
<===检查是否有宽裕的剩余buff空间
-
3613 pfkey_do_dump(pfk);
<===满足条件,重新激活SA dump
-
3614。
-
3615 out_free:
-
3616 skb_free_datagram(sk, skb);
-
3617 out:
-
3618 return err;
-
3619 }
阅读(1453) | 评论(0) | 转发(0) |