/* * 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. */ /* * l2_classify.c */ #include #include /** * @file * @brief L2 input classifier. * * @sa @ref vnet/vnet/classify/vnet_classify.c * @sa @ref vnet/vnet/classify/vnet_classify.h */ /** * @brief l2_input_classifier packet trace record. */ typedef struct { /** interface handle for the ith packet */ u32 sw_if_index; /** graph arc index selected for this packet */ u32 next_index; /** classifier table which provided the final result */ u32 table_index; /** offset in classifier heap of the corresponding session */ u32 session_offset; } l2_input_classify_trace_t; /** * @brief vlib node runtime. */ typedef struct { /** use-case independent main object pointer */ vnet_classify_main_t *vcm; /** l2 input classifier main object pointer */ l2_input_classify_main_t *l2cm; } l2_input_classify_runtime_t; /** Packet trace format function. */ static u8 * format_l2_input_classify_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 *); l2_input_classify_trace_t *t = va_arg (*args, l2_input_classify_trace_t *); s = format (s, "l2-classify: sw_if_index %d, table %d, offset %x, next %d", t->sw_if_index, t->table_index, t->session_offset, t->next_index); return s; } /** l2 input classifier main data structure. */ l2_input_classify_main_t l2_input_classify_main; vlib_node_registration_t l2_input_classify_node; #define foreach_l2_input_classify_error \ _(MISS, "Classify misses") \ _(HIT, "Classify hits") \ _(CHAIN_HIT, "Classify hits after chain walk") \ _(DROP, "L2 Classify Drops") typedef enum { #define _(sym,str) L2_INPUT_CLASSIFY_ERROR_##sym, foreach_l2_input_classify_error #undef _ L2_INPUT_CLASSIFY_N_ERROR, } l2_input_classify_error_t; static char *l2_input_classify_error_strings[] = { #define _(sym,string) string, foreach_l2_input_classify_error #undef _ }; /** * @brief l2 input classifier node. * @node l2-input-classify * * This is the l2 input classifier dispatch node * * @param vm vlib_main_t corresponding to the current thread. * @param node vlib_node_runtime_t data for this node. * @param frame vlib_frame_t whose contents should be dispatched. * * @par Graph mechanics: buffer metadata, next index usage * * @em Uses: * - (l2_input_classify_runtime_t *) * rt->classify_table_index_by_sw_if_index * - Head of the per-interface, per-protocol classifier table chain * for a specific interface. * - @c ~0 => send pkts to the next feature in the L2 feature chain. * - vnet_buffer(b)->sw_if_index[VLIB_RX] * - Indicates the @c sw_if_index value of the interface that the * packet was received on. * - vnet_buffer(b0)->l2.feature_bitmap * - Used to steer packets across l2 features enabled on the interface * - (vnet_classify_entry_t) e0->next_index * - Used to steer traffic when the classifier hits on a session * - (vnet_classify_entry_t) e0->advance * - Signed quantity applied via vlib_buffer_advance * when the classifier hits on a session * - (vnet_classify_table_t) t0->miss_next_index * - Used to steer traffic when the classifier misses * * @em Sets: * - vnet_buffer (b0)->l2_classify.table_index * - Classifier table index of the first classifier table in * the classifier table chain * - vnet_buffer (b0)->l2_classify.hash * - Bounded-index extensible hash corresponding to the * masked fields in the current packet * - vnet_buffer (b0)->l2.feature_bitmap * - Used to steer packets across l2 features enabled on the interface * - vnet_buffer (b0)->l2_classify.opaque_index * - Copied from the classifier session object upon classifier hit * * @em Counters: * - L2_INPUT_CLASSIFY_ERROR_MISS Classifier misses * - L2_INPUT_CLASSIFY_ERROR_HIT Classifier hits * - L2_INPUT_CLASSIFY_ERROR_CHAIN_HIT * Classifier hits in other than the first table */ static uword l2_input_classify_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { u32 n_left_from, *from, *to_next; l2_input_classify_next_t next_index; l2_input_classify_main_t *cm = &l2_input_classify_main; vnet_classify_main_t *vcm = cm->vnet_classify_main; l2_input_classify_runtime_t *rt = (l2_input_classify_runtime_t *) node->runtime_data; u32 feature_bitmap; u32 hits = 0; u32 misses = 0; u32 chain_hits = 0; f64 now; u32 n_next_nodes; n_next_nodes = node->n_next_nodes; now = vlib_time_now (vm); n_left_from = frame->n_vectors; from = vlib_frame_vector_args (frame); /* First pass: compute hash */ while (n_left_from > 2) { vlib_buffer_t *b0, *b1; u32 bi0, bi1; ethernet_header_t *h0, *h1; u32 sw_if_index0, sw_if_index1; u16 type0, type1; int type_index0, type_index1; vnet_classify_table_t *t0, *t1; u32 table_index0, table_index1; u64 hash0, hash1; /* prefetch next iteration */ { vlib_buffer_t *p1, *p2; p1 = vlib_get_buffer (vm, from[1]); p2 = vlib_get_buffer (vm, from[2]); vlib_prefetch_buffer_header (p1, STORE); CLIB_PREFETCH (p1->data, CLIB_CACHE_LINE_BYTES, STORE); vlib_prefetch_buffer_header (p2, STORE); CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); } bi0 = from[0]; b0 = vlib_get_buffer (vm, bi0); h0 = vlib_buffer_get_current (b0); bi1 = from[1]; b1 = vlib_get_buffer (vm, bi1); h1 = vlib_buffer_get_current (b1); sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; vnet_buffer (b0)->l2_classify.table_index = ~0; sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; vnet_buffer (b1)->l2_classify.table_index = ~0; /* Select classifier table based on ethertype */ type0 = clib_net_to_host_u16 (h0->type); type1 = clib_net_to_host_u16 (h1->type); type_index0 = (type0 == ETHERNET_TYPE_IP4) ? L2_INPUT_CLASSIFY_TABLE_IP4 : L2_INPUT_CLASSIFY_TABLE_OTHER; type_index0 = (type0 == ETHERNET_TYPE_IP6) ? L2_INPUT_CLASSIFY_TABLE_IP6 : type_index0; type_index1 = (type1 == ETHERNET_TYPE_IP4) ? L2_INPUT_CLASSIFY_TABLE_IP4 : L2_INPUT_CLASSIFY_TABLE_OTHER; type_index1 = (type1 == ETHERNET_TYPE_IP6) ? L2_INPUT_CLASSIFY_TABLE_IP6 : type_index1; vnet_buffer (b0)->l2_classify.table_index = table_index0 = rt->l2cm->classify_table_index_by_sw_if_index [type_index0][sw_if_index0]; if (table_index0 != ~0) { t0 = pool_elt_at_index (vcm->tables, table_index0); vnet_buffer (b0)->l2_classify.hash = hash0 = vnet_classify_hash_packet (t0, (u8 *) h0); vnet_classify_prefetch_bucket (t0, hash0); } vnet_buffer (b1)->l2_classify.table_index = table_index1 = rt->l2cm->classify_table_index_by_sw_if_index [type_index1][sw_if_index1]; if (table_index1 != ~0) { t1 = pool_elt_at_index (vcm->tables, table_index1); vnet_buffer (b1)->l2_classify.hash = hash1 = vnet_classify_hash_packet (t1, (u8 *) h1); vnet_classify_prefetch_bucket (t1, hash1); } from += 2; n_left_from -= 2; } while (n_left_from > 0) { vlib_buffer_t *b0; u32 bi0; ethernet_header_t *h0; u32 sw_if_index0; u16 type0; u32 type_index0; vnet_classify_table_t *t0; u32 table_index0; u64 hash0; bi0 = from[0]; b0 = vlib_get_buffer (vm, bi0); h0 = vlib_buffer_get_current (b0); sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; vnet_buffer (b0)->l2_classify.table_index = ~0; /* Sel
/*
 * 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.
 */
/*
  Copyright (c) 2005 Eliot Dresselhaus

  Permission is hereby granted, free of charge, to any person obtaining
  a copy of this software and associated documentation files (the
  "Software"), to deal in the Software without restriction, including
  without limitation the rights to use, copy, modify, merge, publish,
  distribute, sublicense, and/or sell copies of the Software, and to
  permit persons to whom the Software is furnished to do so, subject to
  the following conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  OF CONTRACT, TOR