/* * Copyright (c) 2015 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 #define PARSE_DEBUG 0 u16 word_type_index, number_type_index, eof_type_index, rule_eof_type_index, plus_type_index, minus_type_index, star_type_index, slash_type_index, lpar_type_index, rpar_type_index; u8 * format_vlib_parse_value (u8 * s, va_list * args) { vlib_parse_main_t *pm = va_arg (*args, vlib_parse_main_t *); vlib_parse_type_t *type; vlib_parse_value_t *v; u16 type_index; s = format (s, "%d items:\n", vec_len (pm->parse_value)); vec_foreach (v, pm->parse_value) { type_index = v->type; type = pool_elt_at_index (pm->parse_types, type_index); if (type->format_value) s = format (s, "[%d]: %U\n", v - pm->parse_value, type->format_value, v); else s = format (s, "[%d]: (nofun)\n", v - pm->parse_value); } return s; } static u8 * format_vlib_parse_match (u8 * s, va_list * args) { vlib_parse_match_t m = va_arg (*args, vlib_parse_match_t); char *t = 0; switch (m) { #define _(a) case VLIB_PARSE_##a: t = #a; break; foreach_parse_match_type #undef _ default: t = 0; break; } if (t) return format (s, "%s", t); else return format (s, "unknown 0x%x", m); } static u8 * format_vlib_parse_item (u8 * s, va_list * args) { vlib_parse_main_t *pm = va_arg (*args, vlib_parse_main_t *); vlib_parse_item_t *item = va_arg (*args, vlib_parse_item_t *); vlib_parse_type_t *type = pool_elt_at_index (pm->parse_types, item->type); if (item->type == word_type_index) s = format (s, "%s", item->value.as_pointer); else s = format (s, "<%s>", type->name); return s; } static u8 * format_vlib_parse_graph (u8 * s, va_list * args) { vlib_parse_main_t *pm = va_arg (*args, vlib_parse_main_t *); vlib_parse_graph_t *node = va_arg (*args, vlib_parse_graph_t *); vlib_parse_item_t *item; vlib_parse_type_t *type; /* $$$ hash table */ /* *INDENT-OFF* */ pool_foreach (type, pm->parse_types, ({ if (type->rule_index == node - pm->parse_graph) s = format (s, "\n<%s>\n", type->name); })); /* *INDENT-ON* */ if (pm->root_index == (node - pm->parse_graph)) s = format (s, "\n\n"); item = pool_elt_at_index (pm->parse_items, node->item); s = format (s, "[%d] %U ", node - pm->parse_graph, format_vlib_parse_item, pm, item); if (node->peer == (u32) ~ 0) s = format (s, "peer nil "); else s = format (s, "peer %4u ", node->peer); if (node->deeper == (u32) ~ 0) s = format (s, "deeper nil "); else s = format (s, "deeper %4u ", node->deeper); return s; } void dump_parse_graph (void) { vlib_parse_main_t *pm = &vlib_parse_main; vlib_parse_graph_t *node; /* *INDENT-OFF* */ pool_foreach (node, pm->parse_graph, ({ fformat(stdout, "%U\n", format_vlib_parse_graph, pm, node); })); /* *INDENT-ON* */ } always_inline void parse_cleanup_value (vlib_parse_main_t * pm, vlib_parse_value_t * pv) { vlib_parse_type_t *type = pool_elt_at_index (pm->parse_types, pv->type); if (type->value_cleanup_function) type->value_cleanup_function (pv); } static void parse_reset (vlib_parse_main_t * pm, u8 * input) { vlib_lex_token_t *t; vlib_parse_value_t *pv; vlib_lex_reset (pm->lex_main, input); vec_foreach (t, pm->tokens) vlib_lex_cleanup_token (t); vec_foreach (pv, pm->parse_value) parse_cleanup_value (pm, pv); _vec_len (pm->parse_value) = 0; _vec_len (pm->tokens) = 0; pm->current_token_index = 0; } static void parse_help (vlib_parse_main_t * pm, u32 index) { vlib_parse_graph_t *node; vlib_parse_item_t *item; vlib_parse_type_t *type; vlib_main_t *vm = pm->vlib_main; u8 *help_input; int i; help_input = vec_dup (pm->lex_main->input_vector); for (i = vec_len (help_input) - 1; i >= 0; i--) if (help_input[i] == '?') { help_input[i] = 0; _vec_len (help_input) = i; break; } for (i = vec_len (help_input) - 1; i >= 0; i--) { if (help_input[i] != ' ' && help_input[i] != '\t') break; help_input[i] = 0; break; } _vec_len (help_input) = i + 1; while (index != (u32) ~ 0) { node = pool_elt_at_index (pm->parse_graph, index); item = pool_elt_at_index (pm->parse_items, node->item); type = pool_elt_at_index (pm->parse_types, item->type); if (item->type == eof_type_index && vec_len (pm->match_items) == 0) /* do nothing */ ; else if (item->type == word_type_index) vlib_cli_output (vm, "%s %s\n", help_input, item->value.as_pointer); else vlib_cli_output (vm, "%s <%s>\n", help_input, type->name); index = node->peer; } vec_free (help_input); } static vlib_parse_match_t parse_eval_internal (vlib_parse_main_t * pm, u32 index) { vlib_parse_graph_t *node; vlib_parse_item_t *item; vlib_parse_type_t *type; vlib_parse_value_t value, *pv; vlib_parse_match_t rv; u32 *partial_matches = 0; vlib_lex_token_t *t; u32 save_token_index = (u32) ~ 0, save_match_items = 0; int had_value = 0; if (pm->current_token_index >= vec_len (pm->tokens)) return VLIB_PARSE_MATCH_FAIL; /* current token */ t = vec_elt_at_index (pm->tokens, pm->current_token_index); /* Help ? */ if (PREDICT_FALSE (t->token == VLIB_LEX_qmark)) { parse_help (pm, index); _vec_len (pm->match_items) = 0; return VLIB_PARSE_MATCH_DONE; } /* Across all peers at this level of the parse graph */ while (index != (u32) ~ 0) { node = pool_elt_at_index (pm->parse_graph, index); item = pool_elt_at_index (pm->parse_items, node->item); type = pool_elt_at_index (pm->parse_types, item->type); /* * Save the token index. We may have to back up several * trie plies. Type-specific match functions can consume * multiple tokens, and they may not be optimally careful */ save_token_index = pm->current_token_index; save_match_items = vec_len (pm->match_items); vec_add1 (pm->match_items, node->item); if (PARSE_DEBUG > 1) clib_warning ("Try to match token %U against node %d", format_vlib_lex_token, pm->lex_main, t, index); /* Call the type-specific match function */ rv = type->match_function (pm, type, t, &value); if (PARSE_DEBUG > 1) clib_warning ("returned %U", format_vlib_parse_match, rv); switch (rv) { case VLIB_PARSE_MATCH_VALUE: /* * Matched, and returned a value to append to the * set of args passed to the action function */ value.type = item->type; vec_add1 (pm->parse_value, value); had_value = 1; /* fallthrough */ case VLIB_PARSE_MATCH_FULL: unambiguous_partial_match: /* Consume the matched token */ pm->current_token_index++; /* continue matching along this path */ rv = parse_eval_internal (pm, node->deeper); /* this is not the right path */ if (rv == VLIB_PARSE_MATCH_FAIL) { if (had_value) { /* Delete the value */ value = pm->parse_value[vec_len (pm->parse_value) - 1]; parse_cleanup_value (pm, &value); _vec_len (pm->parse_value) -= 1; } /* Continue with the next sibling */ pm->current_token_index = save_token_index; _vec_len (pm->match_items) = save_match_items; index = node->peer; break; } return rv; case VLIB_PARSE_MATCH_PARTIAL: /* Partial (substring) match, remember it but keep going */ vec_add1 (partial_matches, node - pm->parse_graph); index = node->peer; break; case VLIB_PARSE_MATCH_FAIL: /* Continue
/*
 * 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.
 */

#ifndef __BIER_BIT_STRING_H__
#define __BIER_BIT_STRING_H__

#include <vppinfra/byte_order.h>
#include <vppinfra/format.h>

#include <vnet/bier/bier_types.h>

#define BIER_BBS_LEN_TO_BUCKETS(_len) (_len)
#define BIER_BBS_LEN_TO_BITS(_len) (_len * 8)
#define BIER_BBS_LEN_TO_INTS(_len) ((_len) / sizeof(int))
#define BIER_BIT_MASK_BITS_PER_INT (sizeof(int) * 8)

/*
 * bier_find_first_bit_set
 *
 * find the position of the first bit set in a long
 */
static inline int
bier_find_first_bit_string_set (int mask)
{
    return (__builtin_ffs(clib_net_to_host_u32(mask)));
}

extern void bier_bit_string_set_bit(bier_bit_string_t *mask,
                                    bier_bp_t bp);


extern void bier_bit_string_clear_bit(bier_bit_string_t *mask,
                                      bier_bp_t bp);


extern u8 *format_bier_bit_string(u8 * s, va_list * args);

#define BIER_BBS_NUM_INT_BUCKETS(_bbs) \
    (BIER_BBS_LEN_TO_BUCKETS(_bbs->bbs_len) / sizeof(int))

always_inline int
bier_bit_string_is_zero (const bier_bit_string_t *src)
{
    u16 index;

    for (index = 0;
         index < BIER_BBS_NUM_INT_BUCKETS(src);
         index++) {
        if (((int*)src->bbs_buckets)[index] != 0) {
            return (0);
        }
    }
    return (1);
}

always_inline void
bier_bit_string_clear_string (const bier_bit_string_t *src,
                              bier_bit_string_t *dest)
{
    u16 index;

    ASSERT(src->bbs_len == dest->bbs_len);

    for (index = 0;
         index < BIER_BBS_NUM_INT_BUCKETS(src);
         index++) {
        ((int*)dest->bbs_buckets)[index] &= ~(((int*)src->bbs_buckets)[index]);
    }
}

always_inline void
bier_bit_string_logical_and_string (const bier_bit_string_t *src,
                                    bier_bit_string_t *dest)
{
    u16 index;

    ASSERT(src->bbs_len == dest->bbs_len);

    for (index = 0;
         index < BIER_BBS_NUM_INT_BUCKETS<