Beispiel #1
0
static void
ind_ovs_handle_packet_miss(struct ind_ovs_upcall_thread *thread,
                           struct ind_ovs_port *port,
                           struct nl_msg *msg, struct nlattr **attrs)
{
    struct nlmsghdr *nlh = nlmsg_hdr(msg);
    struct genlmsghdr *gnlh = (void *)(nlh + 1);

    struct nlattr *key = attrs[OVS_PACKET_ATTR_KEY];
    struct nlattr *packet = attrs[OVS_PACKET_ATTR_PACKET];
    assert(key && packet);

    struct ind_ovs_parsed_key pkey;
    ind_ovs_parse_key(key, &pkey);

    /* Lookup the flow in the userspace flowtable. */
    struct ind_ovs_flow *flow;
    if (ind_ovs_lookup_flow(&pkey, &flow) != 0) {
        ind_ovs_upcall_request_pktin(pkey.in_port, port, packet, key, OF_PACKET_IN_REASON_NO_MATCH);
        return;
    }

    /* Reuse the incoming message for the packet execute */
    gnlh->cmd = OVS_PACKET_CMD_EXECUTE;
    ind_ovs_translate_actions(&pkey, flow->of_list_action,
                              msg, OVS_PACKET_ATTR_ACTIONS);

    __sync_fetch_and_add(&flow->packets, 1);
    __sync_fetch_and_add(&flow->bytes, nla_len(packet));

    /* Reuse the translated actions for adding the kflow. */
    struct nlattr *actions = nlmsg_find_attr(nlmsg_hdr(msg),
        sizeof(struct genlmsghdr) + sizeof(struct ovs_header),
        OVS_PACKET_ATTR_ACTIONS);

    /* Don't send the packet back out if it would be dropped. */
    if (nla_len(actions) > 0) {
        nlh->nlmsg_pid = 0;
        nlh->nlmsg_seq = 0;
        nlh->nlmsg_flags = NLM_F_REQUEST;
        struct iovec *iovec = &thread->tx_queue[thread->tx_queue_len++];
        iovec->iov_base = nlh;
        iovec->iov_len = nlh->nlmsg_len;
        if (thread->log_upcalls) {
            LOG_VERBOSE("Sending upcall reply:");
            ind_ovs_dump_msg(nlh);
        }
    }

    /* See the comment for ind_ovs_upcall_seen_key. */
    if (ind_ovs_upcall_seen_key(thread, key)) {
        /* Create a kflow with the given key and actions. */
        ind_ovs_bh_request_kflow(key, actions);
    }
}
Beispiel #2
0
static void
ind_ovs_handle_packet_miss(struct ind_ovs_upcall_thread *thread,
                           struct ind_ovs_port *port,
                           struct nl_msg *msg, struct nlattr **attrs)
{
    struct nlmsghdr *nlh = nlmsg_hdr(msg);
    struct genlmsghdr *gnlh = (void *)(nlh + 1);

    struct nlattr *key = attrs[OVS_PACKET_ATTR_KEY];
    struct nlattr *packet = attrs[OVS_PACKET_ATTR_PACKET];
    assert(key && packet);

    struct ind_ovs_parsed_key pkey;
    ind_ovs_parse_key(key, &pkey);

    struct pipeline_result *result = &thread->result;
    pipeline_result_reset(result);
    indigo_error_t err = pipeline_process(&pkey, result);
    if (err < 0) {
        return;
    }

    struct ind_ovs_flow_stats **stats_ptrs = xbuf_data(&result->stats);
    int num_stats_ptrs = xbuf_length(&result->stats) / sizeof(void *);
    int i;
    for (i = 0; i < num_stats_ptrs; i++) {
        struct ind_ovs_flow_stats *stats = stats_ptrs[i];
        __sync_fetch_and_add(&stats->packets, 1);
        __sync_fetch_and_add(&stats->bytes, nla_len(packet));
    }

    /* Check for a single controller action */
    {
        uint32_t actions_length = xbuf_length(&result->actions);
        struct nlattr *first_action = xbuf_data(&result->actions);
        if (actions_length >= NLA_HDRLEN &&
                actions_length == NLA_ALIGN(first_action->nla_len) &&
                first_action->nla_type == IND_OVS_ACTION_CONTROLLER) {
            /*
             * The only action is sending the packet to the controller.
             * It's wasteful to send it all the way through the kernel
             * to be received as another upcall, so request a pktin
             * directly here.
             */
            uint64_t userdata = *XBUF_PAYLOAD(first_action, uint64_t);
            ind_ovs_upcall_request_pktin(pkey.in_port, port, packet, key,
                                         IVS_PKTIN_REASON(userdata),
                                         IVS_PKTIN_METADATA(userdata));
            return;
        }
    }

    /* Reuse the incoming message for the packet execute */
    gnlh->cmd = OVS_PACKET_CMD_EXECUTE;

    struct nlattr *actions = nla_nest_start(msg, OVS_PACKET_ATTR_ACTIONS);
    ind_ovs_translate_actions(&pkey, &result->actions, msg);
    ind_ovs_nla_nest_end(msg, actions);

    /* Don't send the packet back out if it would be dropped. */
    if (nla_len(actions) > 0) {
        nlh->nlmsg_pid = 0;
        nlh->nlmsg_seq = 0;
        nlh->nlmsg_flags = NLM_F_REQUEST;
        struct iovec *iovec = &thread->tx_queue[thread->tx_queue_len++];
        iovec->iov_base = nlh;
        iovec->iov_len = nlh->nlmsg_len;
        if (thread->log_upcalls) {
            LOG_VERBOSE("Sending upcall reply:");
            ind_ovs_dump_msg(nlh);
        }
    }

    /* See the comment for ind_ovs_upcall_seen_key. */
    if (!ind_ovs_disable_kflows && ind_ovs_upcall_seen_key(thread, key)) {
        /* Create a kflow with the given key and actions. */
        ind_ovs_bh_request_kflow(key);
    }
}