/*
 * Copyright (c) 2016 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <vnet/buffer.h>

#include <vnet/bier/bier_fmask.h>
#include <vnet/bier/bier_hdr_inlines.h>
#include <vlib/vlib.h>

static char * bier_output_error_strings[] = {
#define bier_error(n,s) s,
#include <vnet/bier/bier_output_error.def>
#undef bier_error
};

/*
 * Keep these values sematically the same as BIER output
 */
#define foreach_bier_output_next                \
    _(DROP, "bier-drop")

typedef enum {
#define _(s,n) BIER_OUTPUT_NEXT_##s,
    foreach_bier_output_next
#undef _
    BIER_OUTPUT_N_NEXT,
} bier_output_next_t;

typedef enum {
#define bier_error(n,s) BIER_OUTPUT_ERROR_##n,
#include <vnet/bier/bier_output_error.def>
#undef bier_error
    BIER_OUTPUT_N_ERROR,
} bier_output_error_t;

/**
 * Forward declaration
 */
vlib_node_registration_t bier_output_node;
extern vlib_combined_counter_main_t bier_fmask_counters;

/**
 * @brief Packet trace recoed for a BIER output
 */
typedef struct bier_output_trace_t_
{
    u32 next_index;
    index_t bfm_index;
} bier_output_trace_t;

static uword
bier_output (vlib_main_t * vm,
             vlib_node_runtime_t * node,
             vlib_frame_t * from_frame)
{
  vlib_combined_counter_main_t *cm = &bier_fmask_counters;
    u32 n_left_from, next_index, * from, * to_next;
    u32 thread_index;

    thread_index = vlib_get_thread_index ();
    from = vlib_frame_vector_args (from_frame);
    n_left_from = from_frame->n_vectors;

    /*
     * objection your honour! speculation!
     */
    next_index = node->cached_next_index;

    while (n_left_from > 0)
    {
        u32 n_left_to_next;

        vlib_get_next_frame (vm, node, next_index,
                             to_next, n_left_to_next);

        while (n_left_from > 0 && n_left_to_next > 0)
        {
            bier_output_next_t next0;
            bier_bit_string_t bbs;
            vlib_buffer_t * b0;
            bier_fmask_t *bfm0;
            mpls_label_t *h0;
            bier_hdr_t *bh0;
            u32 bfmi0;
            u32 bi0;

            bi0 = from[0];
            to_next[0] = bi0;
            from += 1;
            to_next += 1;
            n_left_from -= 1;
            n_left_to_next -= 1;

            b0 = vlib_get_buffer (vm, bi0);
            bh0 = vlib_buffer_get_current (b0);
            bier_bit_string_init_from_hdr(bh0, &bbs);

            /*
             * In the BIER Lookup node we squirelled away the
             * BIER fmask index as the adj index
             */
            bfmi0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
            bfm0 = bier_fmask_get(bfmi0);

            vlib_increment_combined_counter(
                cm, thread_index, bfmi0, 1,
                vlib_buffer_length_in_chain (vm, b0));

            /*
             * perform the logical AND of the packet's mask with
             * that of the fmask objects, to reset the bits that
             * are only on the shortest path the the fmask NH.
             */
            bier_bit_string_logical_and_string(
                &bfm0->bfm_bits.bfmb_input_reset_string,
                &bbs);

            /*
             * this is the last time we touch the BIER header
             * so flip to network order
             */
            bier_hdr_hton(bh0);

            /*
             * paint the BIER peer's label
             */
            if (!(bfm0->bfm_flags & BIER_FMASK_FLAG_DISP))
            {
                /*
                 * since a BIFT value and a MPLS label are formated the
                 * same, this painting works OK.
                 */
                vlib_buffer_advance(b0, -(word)sizeof(mpls_label_t));
                h0 = vlib_buffer_get_current(b0);
                
                h0[0] = bfm0->bfm_label;

                ((char*)h0)[3]= vnet_buffer(b0)->mpls.ttl - 1;
            }

            /*
             * setup next graph node
             */
            next0 = bfm0->bfm_dpo.dpoi_next_node;
            vnet_buffer(b0)->ip.adj_index[VLIB_TX] = bfm0->bfm_dpo.dpoi_index;

            if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
            {
                bier_output_trace_t *tr;

                tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
                tr->next_index = next0;
                tr->bfm_index = bfmi0;
            }

            vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
                                             to_next, n_left_to_next,
                                             bi0, next0);
        }

        vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    }

    vlib_node_increment_counter (vm, bier_output_node.index,
                                 BIER_OUTPUT_ERROR_NONE,
                                 from_frame->n_vectors);
    return (from_frame->n_vectors);
}

static u8 *
format_bier_output_trace (u8 * s, va_list * args)
{
    CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
    CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
    bier_output_trace_t * t = va_arg (*args, bier_output_trace_t *);

    s = format (s, " next [%d], BFM index %d",
                t->next_index, t->bfm_index);
    return s;
}

VLIB_REGISTER_NODE (bier_output_node) = {
    .function = bier_output,
    .name = "bier-output",
    /* Takes a vector of packets. */
    .vector_size = sizeof (u32),

    .n_errors = BIER_OUTPUT_N_ERROR,
    .error_strings = bier_output_error_strings,

    .n_next_nodes = BIER_OUTPUT_N_NEXT,
    .next_nodes = {
        [BIER_OUTPUT_NEXT_DROP] = "bier-drop",
    },

    .format_trace = format_bier_output_trace,
};
