【OVS2.5.0源码分析】upcall处理线程分析(3)

本文介绍如何将原始Netlink消息转化为Upcall对象的过程。通过解析Netlink消息中的各个属性,如包数据、密钥等,并设置Upcall对象的相关字段,完成消息格式转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一篇介绍了netlink消息的接收,接收到的消息是最原始的消息格式,本篇介绍如何把原始的消息,转化为upcall对象。

1、parse_odp_packet函数

static int
parse_odp_packet(const struct dpif_netlink *dpif, struct ofpbuf *buf,
                 struct dpif_upcall *upcall, int *dp_ifindex)
{
    static const struct nl_policy ovs_packet_policy[] = {
        /* Always present. */
        [OVS_PACKET_ATTR_PACKET] = { .type = NL_A_UNSPEC,
                                     .min_len = ETH_HEADER_LEN },
        [OVS_PACKET_ATTR_KEY] = { .type = NL_A_NESTED },

        /* OVS_PACKET_CMD_ACTION only. */
        [OVS_PACKET_ATTR_USERDATA] = { .type = NL_A_UNSPEC, .optional = true },
        [OVS_PACKET_ATTR_EGRESS_TUN_KEY] = { .type = NL_A_NESTED, .optional = true },
        [OVS_PACKET_ATTR_ACTIONS] = { .type = NL_A_NESTED, .optional = true },
        [OVS_PACKET_ATTR_MRU] = { .type = NL_A_U16, .optional = true }
    };

    struct ovs_header *ovs_header;
    struct nlattr *a[ARRAY_SIZE(ovs_packet_policy)];
    struct nlmsghdr *nlmsg;
    struct genlmsghdr *genl;
    struct ofpbuf b;
    int type;

    ofpbuf_use_const(&b, buf->data, buf->size);

    nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);   //获取nlmsghdr信息
    genl = ofpbuf_try_pull(&b, sizeof *genl);     //获取genlmsghdr信息
    ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header);  //获取ovs_header信息
    if (!nlmsg || !genl || !ovs_header
        || nlmsg->nlmsg_type != ovs_packet_family
        || !nl_policy_parse(&b, 0, ovs_packet_policy, a,       //获取其他属性信息
                            ARRAY_SIZE(ovs_packet_policy))) {
        return EINVAL;
    }

    type = (genl->cmd == OVS_PACKET_CMD_MISS ? DPIF_UC_MISS
            : genl->cmd == OVS_PACKET_CMD_ACTION ? DPIF_UC_ACTION
            : -1);
    if (type < 0) {
        return EINVAL;
    }

    /* (Re)set ALL fields of '*upcall' on successful return. */
    upcall->type = type;
    upcall->key = CONST_CAST(struct nlattr *,
                             nl_attr_get(a[OVS_PACKET_ATTR_KEY]));
    upcall->key_len = nl_attr_get_size(a[OVS_PACKET_ATTR_KEY]);
    dpif_flow_hash(&dpif->dpif, upcall->key, upcall->key_len, &upcall->ufid);
    upcall->userdata = a[OVS_PACKET_ATTR_USERDATA];
    upcall->out_tun_key = a[OVS_PACKET_ATTR_EGRESS_TUN_KEY];
    upcall->actions = a[OVS_PACKET_ATTR_ACTIONS];
    upcall->mru = a[OVS_PACKET_ATTR_MRU];

    /* Allow overwriting the netlink attribute header without reallocating. */
    dp_packet_use_stub(&upcall->packet,       //构建upcall->packet对象,包括base指针、data指针、长度等信息
                    CONST_CAST(struct nlattr *,
                               nl_attr_get(a[OVS_PACKET_ATTR_PACKET])) - 1,
                    nl_attr_get_size(a[OVS_PACKET_ATTR_PACKET]) +
                    sizeof(struct nlattr));
    dp_packet_set_data(&upcall->packet,
                    (char *)dp_packet_data(&upcall->packet) + sizeof(struct nlattr));
    dp_packet_set_size(&upcall->packet, nl_attr_get_size(a[OVS_PACKET_ATTR_PACKET]));

    *dp_ifindex = ovs_header->dp_ifindex;

    return 0;
}
2、nl_policy_parse函数

/* Parses the 'msg' starting at the given 'nla_offset' as a sequence of Netlink
 * attributes.  'policy[i]', for 0 <= i < n_attrs, specifies how the attribute
 * with nla_type == i is parsed; a pointer to attribute i is stored in
 * attrs[i].  Returns true if successful, false on failure.
 *
 * If the Netlink attributes in 'msg' follow a Netlink header and a Generic
 * Netlink header, then 'nla_offset' should be NLMSG_HDRLEN + GENL_HDRLEN. */
bool
nl_policy_parse(const struct ofpbuf *msg, size_t nla_offset,
                const struct nl_policy policy[],
                struct nlattr *attrs[], size_t n_attrs)
{
    struct nlattr *nla;
    size_t left;
    size_t i;

    memset(attrs, 0, n_attrs * sizeof *attrs);

    if (msg->size < nla_offset) {
        VLOG_DBG_RL(&rl, "missing headers in nl_policy_parse");
        return false;
    }

    NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, nla_offset, 0),    //获取netlink的其他属性
                      msg->size - nla_offset)
    {
        uint16_t type = nl_attr_type(nla);
        if (type < n_attrs && policy[type].type != NL_A_NO_ATTR) {
            const struct nl_policy *e = &policy[type];
            if (!nl_attr_validate(nla, e)) {
                return false;
            }
            if (attrs[type]) {
                VLOG_DBG_RL(&rl, "duplicate attr %"PRIu16, type);
            }
            attrs[type] = nla;
        }
    }
    if (left) {
        VLOG_DBG_RL(&rl, "attributes followed by garbage");
        return false;
    }

    for (i = 0; i < n_attrs; i++) {   //检查必须字段是否有值
        const struct nl_policy *e = &policy[i];
        if (!e->optional && e->type != NL_A_NO_ATTR && !attrs[i]) {
            VLOG_DBG_RL(&rl, "required attr %"PRIuSIZE" missing", i);
            return false;
        }
    }
    return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值