- see draft-ietf-bier-mpls-encapsulation-10
- midpoint, head and tail functions
- supported payload protocols; IPv4 and IPv6 only.

Change-Id: I59d7363bb6fdfdce8e4016a68a9c8f5a5e5791cb
Signed-off-by: Neale Ranns <nranns@cisco.com>
This commit is contained in:
Neale Ranns
2017-10-21 10:53:20 -07:00
committed by Damjan Marion
parent a2ff7b8cfc
commit d792d9c01e
73 changed files with 10133 additions and 147 deletions
+158
View File
@@ -5180,6 +5180,8 @@ _(ip_mroute_add_del_reply) \
_(mpls_route_add_del_reply) \
_(mpls_table_add_del_reply) \
_(mpls_ip_bind_unbind_reply) \
_(bier_route_add_del_reply) \
_(bier_table_add_del_reply) \
_(proxy_arp_add_del_reply) \
_(proxy_arp_intfc_enable_disable_reply) \
_(sw_interface_set_unnumbered_reply) \
@@ -5383,6 +5385,8 @@ _(IP_MROUTE_ADD_DEL_REPLY, ip_mroute_add_del_reply) \
_(MPLS_TABLE_ADD_DEL_REPLY, mpls_table_add_del_reply) \
_(MPLS_ROUTE_ADD_DEL_REPLY, mpls_route_add_del_reply) \
_(MPLS_IP_BIND_UNBIND_REPLY, mpls_ip_bind_unbind_reply) \
_(BIER_ROUTE_ADD_DEL_REPLY, bier_route_add_del_reply) \
_(BIER_TABLE_ADD_DEL_REPLY, bier_table_add_del_reply) \
_(PROXY_ARP_ADD_DEL_REPLY, proxy_arp_add_del_reply) \
_(PROXY_ARP_INTFC_ENABLE_DISABLE_REPLY, \
proxy_arp_intfc_enable_disable_reply) \
@@ -8547,6 +8551,154 @@ api_mpls_ip_bind_unbind (vat_main_t * vam)
return ret;
}
static int
api_bier_table_add_del (vat_main_t * vam)
{
unformat_input_t *i = vam->input;
vl_api_bier_table_add_del_t *mp;
u8 is_add = 1;
u32 set = 0, sub_domain = 0, hdr_len = 3;
mpls_label_t local_label = MPLS_LABEL_INVALID;
int ret;
/* Parse args required to build the message */
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "sub-domain %d", &sub_domain))
;
else if (unformat (i, "set %d", &set))
;
else if (unformat (i, "label %d", &local_label))
;
else if (unformat (i, "hdr-len %d", &hdr_len))
;
else if (unformat (i, "add"))
is_add = 1;
else if (unformat (i, "del"))
is_add = 0;
else
{
clib_warning ("parse error '%U'", format_unformat_error, i);
return -99;
}
}
if (MPLS_LABEL_INVALID == local_label)
{
errmsg ("missing label\n");
return -99;
}
/* Construct the API message */
M (BIER_TABLE_ADD_DEL, mp);
mp->bt_is_add = is_add;
mp->bt_label = ntohl (local_label);
mp->bt_tbl_id.bt_set = set;
mp->bt_tbl_id.bt_sub_domain = sub_domain;
mp->bt_tbl_id.bt_hdr_len_id = hdr_len;
/* send it... */
S (mp);
/* Wait for a reply... */
W (ret);
return (ret);
}
static int
api_bier_route_add_del (vat_main_t * vam)
{
unformat_input_t *i = vam->input;
vl_api_bier_route_add_del_t *mp;
u8 is_add = 1;
u32 set = 0, sub_domain = 0, hdr_len = 3, bp = 0;
ip4_address_t v4_next_hop_address;
ip6_address_t v6_next_hop_address;
u8 next_hop_set = 0;
u8 next_hop_proto_is_ip4 = 1;
mpls_label_t next_hop_out_label = MPLS_LABEL_INVALID;
int ret;
/* Parse args required to build the message */
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "%U", unformat_ip4_address, &v4_next_hop_address))
{
next_hop_proto_is_ip4 = 1;
next_hop_set = 1;
}
else if (unformat (i, "%U", unformat_ip6_address, &v6_next_hop_address))
{
next_hop_proto_is_ip4 = 0;
next_hop_set = 1;
}
if (unformat (i, "sub-domain %d", &sub_domain))
;
else if (unformat (i, "set %d", &set))
;
else if (unformat (i, "hdr-len %d", &hdr_len))
;
else if (unformat (i, "bp %d", &bp))
;
else if (unformat (i, "add"))
is_add = 1;
else if (unformat (i, "del"))
is_add = 0;
else if (unformat (i, "out-label %d", &next_hop_out_label))
;
else
{
clib_warning ("parse error '%U'", format_unformat_error, i);
return -99;
}
}
if (!next_hop_set || (MPLS_LABEL_INVALID == next_hop_out_label))
{
errmsg ("next hop / label set\n");
return -99;
}
if (0 == bp)
{
errmsg ("bit=position not set\n");
return -99;
}
/* Construct the API message */
M2 (BIER_ROUTE_ADD_DEL, mp, sizeof (vl_api_fib_path3_t));
mp->br_is_add = is_add;
mp->br_tbl_id.bt_set = set;
mp->br_tbl_id.bt_sub_domain = sub_domain;
mp->br_tbl_id.bt_hdr_len_id = hdr_len;
mp->br_bp = ntohs (bp);
mp->br_n_paths = 1;
mp->br_paths[0].n_labels = 1;
mp->br_paths[0].label_stack[0] = ntohl (next_hop_out_label);
mp->br_paths[0].afi = (next_hop_proto_is_ip4 ? 0 : 1);
if (next_hop_proto_is_ip4)
{
clib_memcpy (mp->br_paths[0].next_hop,
&v4_next_hop_address, sizeof (v4_next_hop_address));
}
else
{
clib_memcpy (mp->br_paths[0].next_hop,
&v6_next_hop_address, sizeof (v6_next_hop_address));
}
/* send it... */
S (mp);
/* Wait for a reply... */
W (ret);
return (ret);
}
static int
api_proxy_arp_add_del (vat_main_t * vam)
{
@@ -22238,6 +22390,12 @@ _(mpls_ip_bind_unbind, \
_(mpls_tunnel_add_del, \
" via <addr> [table-id <n>]\n" \
"sw_if_index <id>] [l2] [del]") \
_(bier_table_add_del, \
"<label> <sub-domain> <set> <bsl> [del]") \
_(bier_route_add_del, \
"<bit-position> <sub-domain> <set> <bsl> via <addr> [table-id <n>]\n" \
"[<intfc> | sw_if_index <id>]" \
"[weight <n>] [del] [multipath]") \
_(proxy_arp_add_del, \
"<lo-ip4-addr> - <hi-ip4-addr> [vrf <n>] [del]") \
_(proxy_arp_intfc_enable_disable, \
+34
View File
@@ -1111,6 +1111,40 @@ libvnet_la_SOURCES += \
vnet/util/radix.c \
vnet/util/trajectory.c
########################################
# BIER
########################################
libvnet_la_SOURCES += \
vnet/bier/bier_bit_string.c \
vnet/bier/bier_entry.c \
vnet/bier/bier_fmask.c \
vnet/bier/bier_fmask_db.c \
vnet/bier/bier_input.c \
vnet/bier/bier_lookup.c \
vnet/bier/bier_output.c \
vnet/bier/bier_table.c \
vnet/bier/bier_types.c \
vnet/bier/bier_test.c \
vnet/bier/bier_api.c \
vnet/bier/bier_drop.c \
vnet/bier/bier_update.c \
vnet/bier/bier_imp_node.c \
vnet/bier/bier_imp.c \
vnet/bier/bier_disp_entry.c \
vnet/bier/bier_disp_lookup_node.c \
vnet/bier/bier_disp_dispatch_node.c \
vnet/bier/bier_disp_table.c
nobase_include_HEADERS += \
vnet/bier/bier_types.h \
vnet/bier/bier_entry.h \
vnet/bier/bier_update.h \
vnet/bier/bier.api.h \
vnet/bier/bier_table.h
API_FILES += vnet/bier/bier.api
########################################
# Plugin client library
########################################
+268
View File
@@ -0,0 +1,268 @@
/*
* 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.
*/
/** \file
This file defines vpp BIER control-plane API messages which are generally
called through a shared memory interface.
*/
vl_api_version 1.0.0
/** \brief BIER Table Indentifier
@param bt_set
@param bt_sub_domain
@param bt_bit_header_length
*/
typeonly define bier_table_id
{
u8 bt_set;
u8 bt_sub_domain;
u8 bt_hdr_len_id;
};
/** \brief BIER Table Add / del route
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param bt_tbl_id - The BIER table-id the route is added in
@param bt_mpls_label - The MPLS label for the table
@param bt_is_add - Is this a route add or delete
*/
autoreply define bier_table_add_del
{
u32 client_index;
u32 context;
vl_api_bier_table_id_t bt_tbl_id;
u32 bt_label;
u8 bt_is_add;
};
define bier_table_dump
{
u32 client_index;
u32 context;
};
define bier_table_details
{
u32 context;
u32 bt_label;
vl_api_bier_table_id_t bt_tbl_id;
};
/** \brief FIB path
@param sw_if_index - index of the interface
@param weight - The weight, for UCMP
@param preference - The preference of the path. lowest preference is prefered
@param is_local - local if non-zero, else remote
@param is_drop - Drop the packet
@param is_unreach - Drop the packet and rate limit send ICMP unreachable
@param is_prohibit - Drop the packet and rate limit send ICMP prohibited
@param afi - the afi of the next hop, IP46_TYPE_IP4=1, IP46_TYPE_IP6=2
@param next_hop[16] - the next hop address
WARNING: this type is replicated, pending cleanup completion
*/
typeonly define fib_path3
{
u32 sw_if_index;
u32 table_id;
u8 weight;
u8 preference;
u8 is_local;
u8 is_drop;
u8 is_unreach;
u8 is_prohibit;
u8 afi;
u8 next_hop[16];
u32 rpf_id;
u8 n_labels;
u32 label_stack[16];
};
/** \brief BIER Route Add / del route
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param br_bp - The Bit-position value
@param br_tbl_id - The BIER table-id the route is added in
@param br_is_add - Is this a route add or delete
@param br_is_replace - Are the paths specfied replacing those already
present or are they to be combined.
@param br_n_paths - The number of paths
@param br_paths - The array of paths
*/
autoreply define bier_route_add_del
{
u32 client_index;
u32 context;
u16 br_bp;
u8 br_is_add;
u8 br_is_replace;
vl_api_bier_table_id_t br_tbl_id;
u8 br_n_paths;
vl_api_fib_path3_t br_paths[br_n_paths];
};
define bier_route_dump
{
u32 client_index;
u32 context;
vl_api_bier_table_id_t br_tbl_id;
};
define bier_route_details
{
u32 client_index;
u32 context;
u16 br_bp;
vl_api_bier_table_id_t br_tbl_id;
u32 br_n_paths;
vl_api_fib_path3_t br_paths[br_n_paths];
};
/** \brief BIER Imposition Add
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param bi_tbl_id - The BIER table-id used to forward post encap
@param bi_src - The source Bit-position in the encap.
@param bi_is_add - Is this a route add or delete
@param bi_n_bytes - The number of bytes in the following bit-string
@param bi_bytes - The bit-string represented as a byte array
*/
define bier_imp_add
{
u32 client_index;
u32 context;
vl_api_bier_table_id_t bi_tbl_id;
u16 bi_src;
u8 bi_is_add;
u8 bi_n_bytes;
u8 bi_bytes[bi_n_bytes];
};
/** \brief Reply for BIER route add / del request
@param context - returned sender context, to match reply w/ request
@param retval - return code
@param bi_index - The index of the created imposition object.
*/
define bier_imp_add_reply
{
u32 context;
i32 retval;
u32 bi_index;
};
/** \brief BIER Imposition Del
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param bi_index - The index of the imposition object (as returned
from the ADD)
*/
autoreply define bier_imp_del
{
u32 client_index;
u32 context;
u32 bi_index;
};
define bier_imp_dump
{
u32 client_index;
u32 context;
};
define bier_imp_details
{
u32 client_index;
u32 context;
vl_api_bier_table_id_t bi_tbl_id;
u16 bi_src;
u8 bi_n_bytes;
u8 bi_bytes[bi_n_bytes];
};
/** \brief BIER Disposition Table Add / del route
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param bt_tbl_id - The BIER Disposition table-id.
*/
autoreply define bier_disp_table_add_del
{
u32 client_index;
u32 context;
u32 bdt_tbl_id;
u8 bdt_is_add;
};
define bier_disp_table_dump
{
u32 client_index;
u32 context;
};
define bier_disp_table_details
{
u32 context;
u32 bdt_tbl_id;
};
/** \brief BIER Disposition Entry Add / del
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param bde_bp - The Bit-position value for the entry
@param bde_tbl_id - The BIER dispositiontable-id the route is added in
@param bde_next_hop_sw_if_index - the nextop interface
@param bde_is_add - Is this a route add or delete
@param bde_payload_proto - The payload protocol for which the next-hop
is added
@param bde_next_hop_table_id - The table ID for the next-hop
@param bde_next_hop_proto_is_ip4 - The next-hop is IPV4
@param bde_next_hop[16] - the nextop address.
Set this to all 0s for dispostion.
*/
autoreply define bier_disp_entry_add_del
{
u32 client_index;
u32 context;
u16 bde_bp;
u32 bde_tbl_id;
u8 bde_is_add;
u8 bde_payload_proto;
u8 bde_n_paths;
vl_api_fib_path3_t bde_paths[bde_n_paths];
};
define bier_disp_entry_dump
{
u32 client_index;
u32 context;
u32 bde_tbl_id;
};
define bier_disp_entry_details
{
u32 context;
u16 bde_bp;
u32 bde_tbl_id;
u8 bde_is_add;
u8 bde_payload_proto;
u8 bde_n_paths;
vl_api_fib_path3_t bde_paths[bde_n_paths];
};
/*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
File diff suppressed because it is too large Load Diff
+109
View File
@@ -0,0 +1,109 @@
/*
* 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/vnet.h>
#include <vnet/bier/bier_types.h>
#include <vnet/bier/bier_bit_string.h>
/*
* the first bit in the first byte is bit position 1.
* bit position 0 is not valid
*/
#define BIER_GET_STRING_POS(_bp, _byte, _bit, _str) \
{ \
_bp--; \
_byte = ((BIER_BBS_LEN_TO_BUCKETS((_str)->bbs_len) - 1 ) - \
(_bp / BIER_BIT_MASK_BITS_PER_BUCKET)); \
_bit = _bp % BIER_BIT_MASK_BITS_PER_BUCKET; \
}
static inline int
bier_bit_pos_is_valid (bier_bp_t bp, const bier_bit_string_t *bbs)
{
if (!((bp <= BIER_BBS_LEN_TO_BITS((bbs)->bbs_len)) &&
(bp >= 1))) {
return (0);
}
return (1);
}
/*
* Validate a bit poistion
*/
#define BIER_BIT_POS_IS_VALID(_bp, _str) \
{ \
if (!bier_bit_pos_is_valid(_bp, _str)) return; \
}
void
bier_bit_string_set_bit (bier_bit_string_t *bit_string,
bier_bp_t bp)
{
bier_bit_mask_bucket_t bmask;
uint16_t byte_pos, bit_pos;
BIER_BIT_POS_IS_VALID(bp, bit_string);
BIER_GET_STRING_POS(bp, byte_pos, bit_pos, bit_string);
bmask = ((bier_bit_mask_bucket_t)1 << bit_pos);
bit_string->bbs_buckets[byte_pos] |= bmask;
}
void
bier_bit_string_clear_bit (bier_bit_string_t *bit_string,
bier_bp_t bp)
{
uint16_t byte_pos, bit_pos;
BIER_BIT_POS_IS_VALID(bp, bit_string);
BIER_GET_STRING_POS(bp, byte_pos, bit_pos, bit_string);
bit_string->bbs_buckets[byte_pos] &= ~(1 << bit_pos);
}
u8 *
format_bier_bit_string (u8 * string,
va_list * args)
{
bier_bit_string_t *bs = va_arg(*args, bier_bit_string_t *);
int leading_marker = 0;
int suppress_zero = 0;
u16 index;
u32 *ptr;
ptr = (u32 *)bs->bbs_buckets;
string = format(string, "%d#", (8 * bs->bbs_len));
for (index = 0; index < (bs->bbs_len/4); index++) {
if (!ptr[index]) {
if (!leading_marker) {
leading_marker = 1;
suppress_zero = 1;
string = format(string, ":");
continue;
}
if (suppress_zero) continue;
} else {
suppress_zero = 0;
}
string = format(string, "%s%X", index ? ":" : "",
clib_net_to_host_u32(ptr[index]));
}
return (string);
}
+107
View File
@@ -0,0 +1,107 @@
/*
* 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_BUKCETS(_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)
{
uint16_t index;
for (index = 0;
index < BIER_BBS_NUM_INT_BUKCETS(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)
{
uint16_t index;
ASSERT(src->bbs_len == dest->bbs_len);
for (index = 0;
index < BIER_BBS_NUM_INT_BUKCETS(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)
{
uint16_t index;
ASSERT(src->bbs_len == dest->bbs_len);
for (index = 0;
index < BIER_BBS_NUM_INT_BUKCETS(src);
index++) {
((int*)dest->bbs_buckets)[index] &= ((int*)src->bbs_buckets)[index];
}
}
always_inline void
bier_bit_string_init (bier_bit_string_t *bbs,
bier_hdr_len_id_t len,
bier_bit_mask_bucket_t *buckets)
{
bbs->bbs_len = bier_hdr_len_id_to_num_bytes(len);
bbs->bbs_buckets = buckets;
}
#endif
+150
View File
@@ -0,0 +1,150 @@
/*
* 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/bier/bier_disp_entry.h>
#include <vnet/bier/bier_hdr_inlines.h>
/**
* @brief A struct to hold tracing information for the MPLS label imposition
* node.
*/
typedef struct bier_disp_dispatch_trace_t_
{
/**
* BIER payload protocol used to dispatch
*/
bier_hdr_proto_id_t pproto;
/**
* RPF-ID packet is tagged with
*/
u32 rpf_id;
} bier_disp_dispatch_trace_t;
always_inline uword
bier_disp_dispatch_inline (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * from_frame)
{
u32 n_left_from, next_index, * from, * to_next;
from = vlib_frame_vector_args (from_frame);
n_left_from = from_frame->n_vectors;
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_hdr_proto_id_t pproto0;
bier_disp_entry_t *bde0;
u32 next0, bi0, bdei0;
const dpo_id_t *dpo0;
vlib_buffer_t * b0;
bier_hdr_t *hdr0;
u32 entropy0;
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);
bdei0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
hdr0 = vlib_buffer_get_current(b0);
bde0 = bier_disp_entry_get(bdei0);
/*
* header is in network order - flip it, we are about to
* consume it anyway
*/
bier_hdr_ntoh(hdr0);
pproto0 = bier_hdr_get_proto_id(hdr0);
entropy0 = bier_hdr_get_entropy(hdr0);
/*
* strip the header and copy the entropy value into
* the packets flow-hash field
* DSCP mumble mumble...
*/
vlib_buffer_advance(b0, (vnet_buffer(b0)->bier.n_bytes +
sizeof(*hdr0)));
vnet_buffer(b0)->ip.flow_hash = entropy0;
/*
* use the payload proto to dispatch to the
* correct stacked DPO.
*/
dpo0 = &bde0->bde_fwd[pproto0].bde_dpo;
next0 = dpo0->dpoi_next_node;
vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
vnet_buffer(b0)->ip.rpf_id = bde0->bde_fwd[pproto0].bde_rpf_id;
if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
{
bier_disp_dispatch_trace_t *tr =
vlib_add_trace (vm, node, b0, sizeof (*tr));
tr->pproto = pproto0;
tr->rpf_id = vnet_buffer(b0)->ip.rpf_id;
}
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);
}
return from_frame->n_vectors;
}
static u8 *
format_bier_disp_dispatch_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_disp_dispatch_trace_t * t;
t = va_arg (*args, bier_disp_dispatch_trace_t *);
s = format (s, "%U", format_bier_hdr_proto, t->pproto);
return (s);
}
static uword
bier_disp_dispatch (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
return (bier_disp_dispatch_inline(vm, node, frame));
}
VLIB_REGISTER_NODE (bier_disp_dispatch_node) = {
.function = bier_disp_dispatch,
.name = "bier-disp-dispatch",
.vector_size = sizeof (u32),
.format_trace = format_bier_disp_dispatch_trace,
.n_next_nodes = 1,
.next_nodes = {
[0] = "bier-drop",
}
};
VLIB_NODE_FUNCTION_MULTIARCH (bier_disp_dispatch_node, bier_disp_dispatch)
File diff suppressed because it is too large Load Diff
+81
View File
@@ -0,0 +1,81 @@
/*
* 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.
*/
/**
* bier_dispositon : The BIER dispositon object
*
* A BIER dispositon object is used to pop the BIER header for for-us
* packets and steer the packet down the payload protocol specific graph
*/
#ifndef __BIER_DISP_ENTRY_H__
#define __BIER_DISP_ENTRY_H__
#include <vnet/bier/bier_types.h>
#include <vnet/fib/fib_types.h>
#include <vnet/dpo/dpo.h>
/**
* The BIER dispositon object
*/
typedef struct bier_disp_entry_t_ {
/**
* The DPO contirubted from the per-payload protocol parents
* on cachline 1.
*/
struct
{
dpo_id_t bde_dpo;
u32 bde_rpf_id;
} bde_fwd[BIER_HDR_N_PROTO];
/**
* number of locks
*/
u32 bde_locks;
/**
* The path-lists used by per-payload protocol parents.
* We don't add the disp entry to the graph as a sibling
* since there is nothing we can do with the updates to
* forwarding.
*/
fib_node_index_t bde_pl[BIER_HDR_N_PROTO];
} bier_disp_entry_t;
extern index_t bier_disp_entry_add_or_lock(void);
extern void bier_disp_entry_path_add(index_t bdei,
bier_hdr_proto_id_t pproto,
const fib_route_path_t *rpaths);
extern int bier_disp_entry_path_remove(index_t bdei,
bier_hdr_proto_id_t pproto,
const fib_route_path_t *rpaths);
extern void bier_disp_entry_unlock(index_t bdi);
extern void bier_disp_entry_lock(index_t bdi);
extern u8* format_bier_disp_entry(u8* s, va_list *ap);
extern void bier_disp_entry_contribute_forwarding(index_t bdi,
dpo_id_t *dpo);
extern bier_disp_entry_t *bier_disp_entry_pool;
always_inline bier_disp_entry_t*
bier_disp_entry_get (index_t bdi)
{
return (pool_elt_at_index(bier_disp_entry_pool, bdi));
}
#endif
+147
View File
@@ -0,0 +1,147 @@
/*
* 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/bier/bier_disp_table.h>
#include <vnet/bier/bier_hdr_inlines.h>
/**
* @brief A struct to hold tracing information for the MPLS label imposition
* node.
*/
typedef struct bier_disp_lookup_trace_t_
{
/**
* BIER source BP used in the lookup - host order
*/
bier_bp_t bp;
/**
* BIER disp table
*/
index_t bdti;
} bier_disp_lookup_trace_t;
/**
* Next nodes from BIER disposition lookup
*/
typedef enum bier_disp_lookup_next_t_
{
BIER_DISP_LOOKUP_NEXT_DROP,
BIER_DISP_LOOKUP_NEXT_DISPATCH,
} bier_disp_lookup_next_t;
#define BIER_DISP_LOOKUP_N_NEXT (BIER_DISP_LOOKUP_NEXT_DISPATCH+1)
always_inline uword
bier_disp_lookup_inline (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * from_frame)
{
u32 n_left_from, next_index, * from, * to_next;
from = vlib_frame_vector_args (from_frame);
n_left_from = from_frame->n_vectors;
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)
{
const bier_hdr_t *hdr0;
vlib_buffer_t * b0;
u32 bdei0, bdti0;
u32 next0, 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);
bdti0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
hdr0 = vlib_buffer_get_current(b0);
/*
* lookup - source is in network order.
*/
bdei0 = bier_disp_table_lookup(bdti0, bier_hdr_get_src_id(hdr0));
if (PREDICT_FALSE(INDEX_INVALID == bdei0))
{
next0 = BIER_DISP_LOOKUP_NEXT_DROP;
}
else
{
next0 = BIER_DISP_LOOKUP_NEXT_DISPATCH;
}
vnet_buffer(b0)->ip.adj_index[VLIB_TX] = bdei0;
if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
{
bier_disp_lookup_trace_t *tr =
vlib_add_trace (vm, node, b0, sizeof (*tr));
tr->bp = clib_net_to_host_u16(bier_hdr_get_src_id(hdr0));
tr->bdti = bdti0;
}
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);
}
return from_frame->n_vectors;
}
static u8 *
format_bier_disp_lookup_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_disp_lookup_trace_t * t;
t = va_arg (*args, bier_disp_lookup_trace_t *);
s = format (s, "tbl:%d src:%d", t->bdti, t->bp);
return (s);
}
static uword
bier_disp_lookup (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
return (bier_disp_lookup_inline(vm, node, frame));
}
VLIB_REGISTER_NODE (bier_disp_lookup_node) = {
.function = bier_disp_lookup,
.name = "bier-disp-lookup",
.vector_size = sizeof (u32),
.format_trace = format_bier_disp_lookup_trace,
.n_next_nodes = BIER_DISP_LOOKUP_N_NEXT,
.next_nodes = {
[BIER_DISP_LOOKUP_NEXT_DROP] = "bier-drop",
[BIER_DISP_LOOKUP_NEXT_DISPATCH] = "bier-disp-dispatch",
}
};
VLIB_NODE_FUNCTION_MULTIARCH (bier_disp_lookup_node, bier_disp_lookup)
File diff suppressed because it is too large Load Diff
+110
View File
@@ -0,0 +1,110 @@
/*
* 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_DISP_TABLE_H__
#define __BIER_DISP_TABLE_H__
#include <vnet/ip/ip.h>
#include <vnet/adj/adj.h>
#include <vnet/dpo/replicate_dpo.h>
#include <vnet/bier/bier_types.h>
#include <vnet/bier/bier_disp_entry.h>
/**
* @brief
* A protocol Independent IP multicast FIB table
*/
typedef struct bier_disp_table_t_
{
/**
* number of locks on the table
*/
u16 bdt_locks;
/**
* Table ID (hash key) for this FIB.
*/
u32 bdt_table_id;
/**
* The lookup DB based on sender BP. Value is the index of the
* BIER disp object.
*/
index_t bdt_db[BIER_BP_MAX];
} bier_disp_table_t;
/**
* @brief
* Format the description/name of the table
*/
extern u8* format_bier_disp_table(u8* s, va_list *ap);
extern void bier_disp_table_entry_path_add(u32 table_id,
bier_bp_t src,
bier_hdr_proto_id_t payload_proto,
const fib_route_path_t *rpath);
extern void bier_disp_table_entry_path_remove(u32 table_id,
bier_bp_t src,
bier_hdr_proto_id_t payload_proto,
const fib_route_path_t *paths);
extern index_t bier_disp_table_find(u32 table_id);
extern index_t bier_disp_table_add_or_lock(u32 table_id);
extern void bier_disp_table_unlock_w_table_id(u32 table_id);
extern void bier_disp_table_unlock(index_t bdti);
extern void bier_disp_table_lock(index_t bdti);
extern void bier_disp_table_contribute_forwarding(index_t bdti,
dpo_id_t *dpo);
/**
* Types and functions to walk all the entries in one BIER Table
*/
typedef void (*bier_disp_table_walk_fn_t)(const bier_disp_table_t *bdt,
const bier_disp_entry_t *bde,
u16 bp,
void *ctx);
extern void bier_disp_table_walk(u32 table_id,
bier_disp_table_walk_fn_t fn,
void *ctx);
/**
* @brief
* Get a pointer to a FIB table
*/
extern bier_disp_table_t *bier_disp_table_pool;
static inline bier_disp_table_t *
bier_disp_table_get (index_t bdti)
{
return (pool_elt_at_index(bier_disp_table_pool, bdti));
}
static inline index_t
bier_disp_table_lookup (index_t bdti,
bier_bp_t src)
{
bier_disp_table_t *bdt;
bdt = bier_disp_table_get(bdti);
return (bdt->bdt_db[src]);
}
#endif
+101
View File
@@ -0,0 +1,101 @@
/*
* 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 <vlib/vlib.h>
#include <vnet/dpo/dpo.h>
#include <vnet/bier/bier_hdr_inlines.h>
typedef struct bier_drop_trace_t_
{
index_t dpi;
} bier_drop_trace_t;
static void
bier_drop_trace (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
u32 *from, n_left;
n_left = frame->n_vectors;
from = vlib_frame_vector_args (frame);
while (n_left >= 1)
{
u32 bi0;
vlib_buffer_t *b0;
bier_drop_trace_t *t0;
bi0 = from[0];
b0 = vlib_get_buffer (vm, bi0);
if (b0->flags & VLIB_BUFFER_IS_TRACED)
{
t0 = vlib_add_trace (vm, node, b0, sizeof(*t0));
t0->dpi = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
}
from += 1;
n_left -= 1;
}
}
static uword
bier_drop (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
u32 *buffers = vlib_frame_vector_args (frame);
uword n_packets = frame->n_vectors;
vlib_error_drop_buffers (vm, node, buffers,
/* stride */ 1,
n_packets,
/* next */ 0,
0, // bier_input_node.index,
0);
if (node->flags & VLIB_NODE_FLAG_TRACE)
bier_drop_trace (vm, node, frame);
return n_packets;
}
static u8 *
format_bier_drop_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_drop_trace_t *t = va_arg (*args, bier_drop_trace_t *);
s = format (s, "dpo-idx %d", t->dpi);
return s;
}
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (bier_drop_node, static) =
{
.function = bier_drop,.
name = "bier-drop",
.vector_size = sizeof (u32),
.format_trace = format_bier_drop_trace,
.n_next_nodes = 1,
.next_nodes = {
[0] = "error-drop",
},
};
File diff suppressed because it is too large Load Diff
+94
View File
@@ -0,0 +1,94 @@
/*
* 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.
*/
/**
* bier_entry : The BIER entry
*
* The interface to the BIER entry is through a bier_entry_t* rather
* than an index. This is becuase the BIER table allocates the entries
* in a contiguous array once and only once when the table is created.
* this is done for forwarding performance. The entry is thus not subject
* to realloc, and does not need to be malloc'd when a route to that
* bit-position is first learned.
*
*/
#ifndef __BIER_ENTRY_H__
#define __BIER_ENTRY_H__
#include <vlib/vlib.h>
#include <vnet/fib/fib_node.h>
#include <vnet/bier/bier_types.h>
/**
* Forward declarations
*/
struct bier_route_update_t_;
struct bier_fmask_db_t_;
/**
* The BIER entry
*
* the BIER entry is the representation of a BIER forwarding egress router (BFER)
* (or the egress PE) that is assigned a bit position.
*/
typedef struct bier_entry_t_ {
/**
* linkage into the FIB graph
*/
fib_node_t be_node;
/**
* The index of the BIER table in which this entry resides
*/
index_t be_bti;
/**
* the bit position this entry represents.
* this is the key table insertion
*/
bier_bp_t be_bp;
/**
* the FIB path-list this entry resolves through.
* the path-list is itself resoved on the entry's fmasks
*/
fib_node_index_t be_path_list;
/**
* sibling index on the path list
*/
fib_node_index_t be_sibling_index;
} bier_entry_t;
extern index_t bier_entry_create(index_t bti,
bier_bp_t bp);
extern void bier_entry_delete(index_t bei);
extern void bier_entry_path_add(index_t bei,
const fib_route_path_t *brp);
extern int bier_entry_path_remove(index_t bei,
const fib_route_path_t *brp);
extern u8* format_bier_entry(u8* s, va_list *ap);
extern void bier_entry_contribute_forwarding(index_t bei,
dpo_id_t *dpo);
extern bier_entry_t *bier_entry_pool;
always_inline bier_entry_t* bier_entry_get(index_t bei)
{
return (&bier_entry_pool[bei]);
}
#endif
File diff suppressed because it is too large Load Diff
+198
View File
@@ -0,0 +1,198 @@
/*
* 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.
*/
/**
* @brief bier_fmask : The BIER fmask
*
* The BIER fmask contains the bitString that is applied to packets that
* egress towards the next-hop. As such the fmask is part of the rewrite
* (adj) for that next-hop. It it thus an extension of the next-hop and in
* no way associated with the bit-position(s) that are reachable through it.
* Fmasks are thus shared by bit-positions that egress throught the same
* nh (BFR-NBR).
* Deag fmasks are also shread in the event that a router has local
* bit-positions. This is necessary to prevent the router recieving two copies
* of each packet. Consequently it also means that they share the same
* disposition data for the global data.
*/
#ifndef __BIER_FMASK_H__
#define __BIER_FMASK_H__
#include <vlib/vlib.h>
#include <vnet/fib/fib_node.h>
#include <vnet/mpls/packet.h>
#include <vnet/dpo/dpo.h>
#include <vnet/bier/bier_types.h>
#include <vnet/bier/bier_fmask_db.h>
/**
* A struct that represents the reference counting of the bits
*/
typedef struct bier_fmask_bits_t_ {
/**
* each bit in the mask needs to be reference counted
* and set/cleared on the 0->1 and 1->0 transitions.
*/
bier_bit_string_t bfmb_input_reset_string;
u32 *bfmb_refs;
/**
* The total number of references to bits set on this mask
* in effect a count of the number of children.
*/
uint32_t bfmb_count;
} bier_fmask_bits_t;
/**
* Flags on fmask
*/
typedef enum bier_fmask_attributes_t_
{
BIER_FMASK_ATTR_FIRST,
BIER_FMASK_ATTR_FORWARDING = BIER_FMASK_ATTR_FIRST,
BIER_FMASK_ATTR_DISP,
BIER_FMASK_ATTR_LAST = BIER_FMASK_ATTR_DISP,
} bier_fmask_attributes_t;
#define BIER_FMASK_ATTR_NAMES { \
[BIER_FMASK_ATTR_FORWARDING] = "forwarding", \
[BIER_FMASK_ATTR_DISP] = "disposition", \
}
#define FOR_EACH_BIER_FMASK_ATTR(_item) \
for (_item = BIER_FMASK_ATTR_FIRST; \
_item <= BIER_FMASK_ATTR_LAST; \
_item++)
typedef enum bier_fmask_flags_t_
{
BIER_FMASK_FLAG_FORWARDING = (1 << BIER_FMASK_ATTR_FORWARDING),
BIER_FMASK_FLAG_DISP = (1 << BIER_FMASK_ATTR_DISP),
} bier_fmask_flags_t;
/**
* An outgoing BIER mask. aka forwarding bit mask (in the RFCs)
*
* This mask's function is two-fold
* 1 - it is logical-AND with the input packet header to produce the
* output packet header
* 2 - it is logical NAND with the input packet header to modify the bit-mask
* for the next lookup
*/
typedef struct bier_fmask_t_ {
/**
* The BIER fmask is a child of a FIB entry in the FIB graph.
*/
fib_node_t bfm_node;
/**
* operational/state flags on the fmask
*/
bier_fmask_flags_t bfm_flags;
/**
* The bits, and their ref counts, that are set on this mask
* This mask changes as BIER entries link to and from this fmask
*/
bier_fmask_bits_t bfm_bits;
struct
{
/**
* The key to this fmask - used for store/lookup in the DB
*/
bier_fmask_id_t bfm_id;
/**
* The BIER Table this Fmask is used in
*/
index_t bfm_fib_index;
};
union
{
/**
* For forwarding via a next-hop
*/
struct
{
/**
* The parent fib entry
*/
fib_node_index_t bfm_fei;
/**
* The MPLS label to paint on the header during forwarding
*/
mpls_label_t bfm_label;
};
/**
* For disposition
*/
struct
{
/**
* The parent disposition table object
*/
index_t bfm_disp;
};
};
/**
* the index of this fmask in the parent's child list.
*/
u32 bfm_sibling;
/**
* The index into the adj table for the adj that
* this fmask resolves via
*/
dpo_id_t bfm_dpo;
} bier_fmask_t;
extern void bier_fmask_link(index_t bfmi, bier_bp_t bp);
extern void bier_fmask_unlink(index_t bfmi, bier_bp_t bp);
extern void bier_fmask_unlock(index_t bfmi);
extern void bier_fmask_lock(index_t bfmi);
extern index_t bier_fmask_create_and_lock(const bier_fmask_id_t *fmid,
index_t bti,
const fib_route_path_t *rpath);
extern u8* format_bier_fmask(u8 *s, va_list *ap);
extern void bier_fmask_contribute_forwarding(index_t bfmi,
dpo_id_t *dpo);
extern u32 bier_fmask_child_add (fib_node_index_t fib_entry_index,
fib_node_type_t child_type,
fib_node_index_t child_index);
extern void bier_fmask_child_remove (fib_node_index_t fib_entry_index,
u32 sibling_index);
/*
* provided for fast data-path access
*/
bier_fmask_t *bier_fmask_pool;
static inline bier_fmask_t *
bier_fmask_get (u32 index)
{
return (pool_elt_at_index(bier_fmask_pool, index));
}
#endif
+161
View File
@@ -0,0 +1,161 @@
/*
* 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/bier/bier_fmask_db.h>
#include <vnet/bier/bier_fmask.h>
/**
* Global Table of fmask objects
* The key into this table includes the table's key and the fmask's key,
* so there could be a DB per-table. But it is more efficient
* at forwarding time to extract the fmask from a single global table
* which is hot in dcache.
*
* The table's key is part of this DB key, since the fmasks therein build up
* their forwarding mask based on the routes that resolve through
* it, so cross polination would be bad.
*/
typedef struct bier_fmask_db_t_ {
/**
* hash table for underlying storage
*/
mhash_t bfdb_hash;
/**
* Pool for memory
*/
struct bier_fmask_t_ *bfdb_pool;
} bier_fmask_db_t;
/**
* The key used in the fmask DB to compare fmask objects.
* There is one global DB, so we need to use the table's ID and the fmasks ID
*/
typedef struct bier_fmask_db_key_t_ {
bier_fmask_id_t bfmdbk_fm_id;
index_t bfmdbk_tbl_id;
} bier_fmask_db_key_t;
// TODO packed?
/**
* Single fmask DB
*/
static bier_fmask_db_t bier_fmask_db;
u32
bier_fmask_get_index (const bier_fmask_t *bfm)
{
return (bfm - bier_fmask_db.bfdb_pool);
}
u32
bier_fmask_db_find_or_create_and_lock (index_t bti,
const bier_fmask_id_t *fmid,
const fib_route_path_t *rpath)
{
bier_fmask_db_key_t key;
u32 index;
uword *p;
/*
* there be padding in that thar key, and it's
* used as a memcmp in the mhash.
*/
memset(&key, 0, sizeof(key));
key.bfmdbk_tbl_id = bti;
key.bfmdbk_fm_id = *fmid;
index = INDEX_INVALID;
p = mhash_get (&bier_fmask_db.bfdb_hash, &key);
if (NULL == p)
{
/*
* adding a new fmask object
*/
index = bier_fmask_create_and_lock(fmid, bti, rpath);
mhash_set (&bier_fmask_db.bfdb_hash, &key, index, 0 /*old_value*/);
}
else
{
index = p[0];
bier_fmask_lock(index);
}
return (index);
}
u32
bier_fmask_db_find (index_t bti,
const bier_fmask_id_t *fmid)
{
bier_fmask_db_key_t key;
u32 index;
uword *p;
/*
* there be padding in that thar key, and it's
* used as a memcmp in the mhash.
*/
memset(&key, 0, sizeof(key));
key.bfmdbk_tbl_id = bti;
key.bfmdbk_fm_id = *fmid;
index = INDEX_INVALID;
p = mhash_get(&bier_fmask_db.bfdb_hash, &key);
if (NULL != p)
{
index = p[0];
}
return (index);
}
void
bier_fmask_db_remove (index_t bti,
const bier_fmask_id_t *fmid)
{
bier_fmask_db_key_t key = {
.bfmdbk_tbl_id = bti,
.bfmdbk_fm_id = *fmid,
};
uword *p;
p = mhash_get (&bier_fmask_db.bfdb_hash, &key);
if (NULL == p) {
/*
* remove a non-exitant entry - oops
*/
ASSERT (!"remove non-existant fmask");
} else {
mhash_unset (&(bier_fmask_db.bfdb_hash), &key, 0);
}
}
clib_error_t *
bier_fmask_db_module_init (vlib_main_t *vm)
{
mhash_init (&bier_fmask_db.bfdb_hash,
sizeof(uword),
sizeof(bier_fmask_db_key_t));
return (NULL);
}
VLIB_INIT_FUNCTION (bier_fmask_db_module_init);
+61
View File
@@ -0,0 +1,61 @@
/*
* 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.
*/
/**
* @brief bier_fmask_db : The BIER fmask Database
*/
#ifndef __BIER_FMASK_DB_H__
#define __BIER_FMASK_DB_H__
#include <vnet/ip/ip.h>
#include <vnet/bier/bier_types.h>
/**
* Foward declarations
*/
struct bier_fmask_t_;
typedef enum bier_hdr_type_t_ {
BIER_HDR_IN_IP6,
BIER_HDR_O_MPLS,
} bier_hdr_type_t;
typedef struct bier_fmask_id_t_ {
/**
* Type of BIER header this fmask supports
*/
bier_hdr_type_t bfmi_hdr_type;
/**
* next-hop of the peer
*/
ip46_address_t bfmi_nh;
} bier_fmask_id_t;
extern u32
bier_fmask_db_find_or_create_and_lock(index_t bti,
const bier_fmask_id_t *fmid,
const fib_route_path_t *rpath);
extern u32
bier_fmask_db_find(index_t bti,
const bier_fmask_id_t *fmid);
extern void
bier_fmask_db_remove(index_t bti,
const bier_fmask_id_t *fmid);
#endif
+217
View File
@@ -0,0 +1,217 @@
/*
* 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.
*/
/**
* @brief The BIER inline functions acting on the bier header
*/
#ifndef __BIER_HDR_INLINES_H__
#define __BIER_HDR_INLINES_H__
#include <vppinfra/byte_order.h>
#include <vppinfra/string.h>
#include <vnet/bier/bier_types.h>
#include <vnet/bier/bier_bit_string.h>
#include <vnet/ip/ip6_packet.h>
/**
* Mask and shift values for the fields incorporated
* into the header's first word
*/
#define BIER_HDR_1ST_NIBBLE_MASK 0xf0000000
#define BIER_HDR_VERSION_FIELD_MASK 0x0f000000
#define BIER_HDR_LEN_FIELD_MASK 0x00f00000
#define BIER_HDR_ENTROPY_FIELD_MASK 0x000fffff
#define BIER_HDR_1ST_NIBBLE_SHIFT 28
#define BIER_HDR_VERSION_FIELD_SHIFT 24
#define BIER_HDR_LEN_FIELD_SHIFT 20
#define BIER_HDR_ENTROPY_FIELD_SHIFT 0
#define BIER_HDR_1ST_NIBBLE_VALUE 0x5
/**
* Mask and shift values for fields in the headers trainling word
*/
#define BIER_HDR_PROTO_FIELD_MASK 0x003f
#define BIER_HDR_OAM_FIELD_MASK 0xc000
#define BIER_HDR_DSCP_FIELD_MASK 0x0fc0
#define BIER_HDR_DSCP_FIELD_SHIFT 6
#define BIER_HDR_PROTO_FIELD_SHIFT 0
#define BIER_HDR_OAM_FIELD_SHIFT 14
static inline bier_hdr_version_t
bier_hdr_get_version (const bier_hdr_t *bier_hdr)
{
return ((bier_hdr->bh_first_word &
BIER_HDR_VERSION_FIELD_MASK) >>
BIER_HDR_VERSION_FIELD_SHIFT);
}
static inline bier_hdr_len_id_t
bier_hdr_get_len_id (const bier_hdr_t *bier_hdr)
{
return ((bier_hdr->bh_first_word &
BIER_HDR_LEN_FIELD_MASK) >>
BIER_HDR_LEN_FIELD_SHIFT);
}
static inline bier_hdr_entropy_t
bier_hdr_get_entropy (const bier_hdr_t *bier_hdr)
{
return ((bier_hdr->bh_first_word &
BIER_HDR_ENTROPY_FIELD_MASK) >>
BIER_HDR_ENTROPY_FIELD_SHIFT);
}
static inline void
bier_hdr_1st_nibble (bier_hdr_t *hdr)
{
hdr->bh_first_word &= ~(BIER_HDR_1ST_NIBBLE_MASK);
hdr->bh_first_word |= (BIER_HDR_1ST_NIBBLE_VALUE <<
BIER_HDR_1ST_NIBBLE_SHIFT);
}
static inline u8
bier_hdr_get_1st_nibble (bier_hdr_t *hdr)
{
return ((hdr->bh_first_word & BIER_HDR_1ST_NIBBLE_MASK) >>
BIER_HDR_1ST_NIBBLE_SHIFT);
}
static inline void
bier_hdr_set_version (bier_hdr_t *hdr,
bier_hdr_version_t version)
{
hdr->bh_first_word &= ~(BIER_HDR_VERSION_FIELD_MASK);
hdr->bh_first_word |= (version << BIER_HDR_VERSION_FIELD_SHIFT);
}
static inline void
bier_hdr_set_len_id (bier_hdr_t *hdr,
bier_hdr_len_id_t len)
{
hdr->bh_first_word &= ~(BIER_HDR_LEN_FIELD_MASK);
hdr->bh_first_word |= (len << BIER_HDR_LEN_FIELD_SHIFT);
}
static inline void
bier_hdr_set_entropy (bier_hdr_t *hdr,
bier_hdr_entropy_t entropy)
{
entropy = entropy & BIER_HDR_ENTROPY_FIELD_MASK;
hdr->bh_first_word &= ~(BIER_HDR_ENTROPY_FIELD_MASK);
hdr->bh_first_word |= (entropy << BIER_HDR_ENTROPY_FIELD_SHIFT);
}
#define BIER_HDR_FIRST_WORD(version, len, entropy) \
((BIER_HDR_1ST_NIBBLE_VALUE << \
BIER_HDR_1ST_NIBBLE_SHIFT) | \
(version << BIER_HDR_VERSION_FIELD_SHIFT) | \
(len << BIER_HDR_LEN_FIELD_SHIFT) | \
((entropy & BIER_HDR_ENTROPY_FIELD_MASK) \
<< BIER_HDR_ENTROPY_FIELD_SHIFT))
static inline void
bier_hdr_ntoh (bier_hdr_t *bier_hdr)
{
bier_hdr->bh_first_word = clib_net_to_host_u32(bier_hdr->bh_first_word);
bier_hdr->bh_oam_dscp_proto = clib_net_to_host_u16(bier_hdr->bh_oam_dscp_proto);
bier_hdr->bh_bfr_id = clib_net_to_host_u16(bier_hdr->bh_bfr_id);
}
static inline void
bier_hdr_hton (bier_hdr_t *bier_hdr)
{
bier_hdr->bh_first_word = clib_host_to_net_u32(bier_hdr->bh_first_word);
bier_hdr->bh_oam_dscp_proto = clib_host_to_net_u16(bier_hdr->bh_oam_dscp_proto);
bier_hdr->bh_bfr_id = clib_host_to_net_u16(bier_hdr->bh_bfr_id);
}
static inline bier_hdr_src_id_t
bier_hdr_get_src_id (const bier_hdr_t *bier_hdr)
{
return (bier_hdr->bh_bfr_id);
}
static inline void
bier_hdr_set_src_id (bier_hdr_t *bier_hdr,
bier_hdr_src_id_t src_id)
{
bier_hdr->bh_bfr_id = src_id;
}
static inline void
bier_hdr_set_proto_id (bier_hdr_t *bier_hdr,
bier_hdr_proto_id_t proto)
{
bier_hdr->bh_oam_dscp_proto &= ~(BIER_HDR_PROTO_FIELD_MASK);
bier_hdr->bh_oam_dscp_proto |= (proto << BIER_HDR_PROTO_FIELD_SHIFT);
}
static inline bier_hdr_proto_id_t
bier_hdr_get_proto_id (const bier_hdr_t *bier_hdr)
{
return ((bier_hdr->bh_oam_dscp_proto & BIER_HDR_PROTO_FIELD_MASK) >>
BIER_HDR_PROTO_FIELD_SHIFT);
}
static inline void
bier_hdr_clear (bier_hdr_t *bier_hdr)
{
memset(&bier_hdr->bh_bit_string, 0,
bier_hdr_len_id_to_num_buckets(
bier_hdr_get_len_id(bier_hdr)));
}
static inline void
bier_hdr_init (bier_hdr_t *bier_hdr,
bier_hdr_version_t version,
bier_hdr_proto_id_t proto,
bier_hdr_len_id_t len,
bier_hdr_entropy_t entropy,
bier_bp_t src)
{
bier_hdr_1st_nibble(bier_hdr);
bier_hdr_set_version(bier_hdr, version);
bier_hdr_set_len_id(bier_hdr, len);
bier_hdr_set_entropy(bier_hdr, entropy);
bier_hdr_set_proto_id(bier_hdr, proto);
bier_hdr_set_src_id(bier_hdr, src);
bier_hdr_clear(bier_hdr);
}
static inline size_t
bier_hdr_str_num_bytes (const bier_hdr_t *bier_hdr)
{
return (bier_hdr_len_id_to_num_bytes(
bier_hdr_get_len_id(bier_hdr)));
}
static inline size_t
bier_hdr_num_bytes (const bier_hdr_t *bier_hdr)
{
return (sizeof(bier_hdr_t) +
bier_hdr_str_num_bytes(bier_hdr));
}
static inline void
bier_bit_string_init_from_hdr (bier_hdr_t *bier_hdr,
bier_bit_string_t *bit_string)
{
bit_string->bbs_len = bier_hdr_str_num_bytes(bier_hdr);
bit_string->bbs_buckets = bier_hdr->bh_bit_string;
}
#endif
+288
View File
@@ -0,0 +1,288 @@
/*
* Copyright (c) 2017 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.
*/
/**
* bier_imposition : The BIER imposition object
*
* A BIER imposition object is present in the IP mcast output list
* and represents the imposition of a BIER bitmask. After BIER header
* imposition the packet is forward within the appropriate/specifid
* BIER table
*/
#include <vnet/bier/bier_imp.h>
#include <vnet/bier/bier_table.h>
#include <vnet/bier/bier_hdr_inlines.h>
#include <vnet/fib/fib_node.h>
#include <vnet/mpls/mpls_types.h>
/**
* The memory pool of all imp objects
*/
bier_imp_t *bier_imp_pool;
/**
* When constructing the BIER imp ID from an index and BSL, shift
* the BSL this far
*/
#define BIER_IMP_ID_HLEN_SHIFT 24
static void
bier_imp_lock_i (bier_imp_t *bi)
{
bi->bi_locks++;
}
void
bier_imp_lock (index_t bii)
{
bier_imp_lock_i(bier_imp_get(bii));
}
static index_t
bier_imp_get_index(bier_imp_t *bi)
{
return (bi - bier_imp_pool);
}
index_t
bier_imp_add_or_lock (const bier_table_id_t *bti,
bier_bp_t sender,
const bier_bit_string_t *bs)
{
bier_imp_t *bi = NULL;
fib_protocol_t fproto;
index_t btii;
pool_get_aligned(bier_imp_pool, bi, CLIB_CACHE_LINE_BYTES);
bi->bi_tbl = *bti;
btii = bier_table_add_or_lock(bti, MPLS_LABEL_INVALID);
/*
* init the BIER header we will paint on in the data plane
*/
bier_hdr_init(&bi->bi_hdr,
BIER_HDR_VERSION_1,
BIER_HDR_PROTO_INVALID, // filled in later
bti->bti_hdr_len,
0, // entropy
sender);
bier_hdr_hton(&bi->bi_hdr);
clib_memcpy(&bi->bi_bits, bs->bbs_buckets, bs->bbs_len);
bier_imp_lock_i(bi);
/*
* get and stack on the forwarding info from the table
*/
FOR_EACH_FIB_IP_PROTOCOL(fproto)
{
/*
* initialise to invalid first, lest we pick up garbage
* from the pool alloc
*/
dpo_id_t dpo = DPO_INVALID;
bi->bi_dpo[fproto] = dpo;
bier_table_contribute_forwarding(btii, &dpo);
dpo_stack(DPO_BIER_IMP, fib_proto_to_dpo(fproto),
&bi->bi_dpo[fproto],
&dpo);
dpo_reset(&dpo);
}
return (bier_imp_get_index(bi));
}
void
bier_imp_unlock (index_t bii)
{
fib_protocol_t fproto;
bier_imp_t *bi;
if (INDEX_INVALID == bii)
{
return;
}
bi = bier_imp_get(bii);
bi->bi_locks--;
if (0 == bi->bi_locks)
{
bier_table_unlock(&bi->bi_tbl);
FOR_EACH_FIB_IP_PROTOCOL(fproto)
{
dpo_reset(&bi->bi_dpo[fproto]);
}
pool_put(bier_imp_pool, bi);
}
}
u8*
format_bier_imp (u8* s, va_list *args)
{
index_t bii = va_arg (*args, index_t);
u32 indent = va_arg(*args, u32);
bier_show_flags_t flags = va_arg(*args, bier_show_flags_t);
bier_imp_t *bi;
bi = bier_imp_get(bii);
s = format(s, "bier-imp:[%d]: tbl:[%U] hdr:[%U]",
bier_imp_get_index(bi),
format_bier_table_id, &bi->bi_tbl,
format_bier_hdr, &bi->bi_hdr);
if (BIER_SHOW_DETAIL & flags)
{
bier_bit_string_t bbs;
bier_hdr_t copy;
copy = bi->bi_hdr;
bier_hdr_ntoh(&copy);
bier_bit_string_init(&bbs,
bier_hdr_get_len_id(&copy),
bi->bi_bits.bits);
s = format(s, "\n%U%U",
format_white_space, indent,
format_bier_bit_string, &bbs);
s = format(s, "\n%U%U",
format_white_space, indent,
format_dpo_id, &bi->bi_dpo, indent+2);
}
return (s);
}
void
bier_imp_contribute_forwarding (index_t bii,
dpo_proto_t proto,
dpo_id_t *dpo)
{
dpo_set(dpo, DPO_BIER_IMP, proto, bii);
}
const static char* const bier_imp_ip4_nodes[] =
{
"bier-imp-ip4",
NULL,
};
const static char* const bier_imp_ip6_nodes[] =
{
"bier-imp-ip6",
NULL,
};
const static char* const * const bier_imp_nodes[DPO_PROTO_NUM] =
{
[DPO_PROTO_IP4] = bier_imp_ip4_nodes,
[DPO_PROTO_IP6] = bier_imp_ip6_nodes,
};
static void
bier_imp_dpo_lock (dpo_id_t *dpo)
{
bier_imp_lock(dpo->dpoi_index);
}
static void
bier_imp_dpo_unlock (dpo_id_t *dpo)
{
bier_imp_unlock(dpo->dpoi_index);
}
static void
bier_imp_dpo_mem_show (void)
{
fib_show_memory_usage("BIER imposition",
pool_elts(bier_imp_pool),
pool_len(bier_imp_pool),
sizeof(bier_imp_t));
}
static u8*
format_bier_imp_dpo (u8* s, va_list *ap)
{
index_t index = va_arg(*ap, index_t);
u32 indent = va_arg(*ap, u32);
s = format(s, "%U", format_bier_imp, index, indent, BIER_SHOW_DETAIL);
return (s);
}
const static dpo_vft_t bier_imp_vft = {
.dv_lock = bier_imp_dpo_lock,
.dv_unlock = bier_imp_dpo_unlock,
.dv_format = format_bier_imp_dpo,
.dv_mem_show = bier_imp_dpo_mem_show,
};
clib_error_t *
bier_imp_db_module_init (vlib_main_t *vm)
{
dpo_register(DPO_BIER_IMP, &bier_imp_vft, bier_imp_nodes);
return (NULL);
}
VLIB_INIT_FUNCTION (bier_imp_db_module_init);
static clib_error_t *
show_bier_imp (vlib_main_t * vm,
unformat_input_t * input,
vlib_cli_command_t * cmd)
{
bier_imp_t *bi;
index_t bii;
bii = INDEX_INVALID;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
if (unformat (input, "%d", &bii))
;
else
{
break;
}
}
if (INDEX_INVALID == bii)
{
pool_foreach(bi, bier_imp_pool,
({
vlib_cli_output(vm, "%U", format_bier_imp,
bier_imp_get_index(bi),
1,
BIER_SHOW_BRIEF);
}));
}
else
{
vlib_cli_output(vm, "%U", format_bier_imp, bii, 1,
BIER_SHOW_DETAIL);
}
return (NULL);
}
VLIB_CLI_COMMAND (show_bier_imp_node, static) = {
.path = "show bier imp",
.short_help = "show bier imp [index]",
.function = show_bier_imp,
};
+87
View File
@@ -0,0 +1,87 @@
/*
* 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.
*/
/**
* bier_imposition : The BIER imposition object
*
* A BIER imposition object is present in the IP mcast output list
* and represents the imposition of a BIER bitmask. After BIER header
* imposition the packet is forward within the appropriate/specifid
* BIER table
*/
#ifndef __BIER_IMPOSITION_H__
#define __BIER_IMPOSITION_H__
#include <vnet/bier/bier_types.h>
#include <vnet/fib/fib_types.h>
#include <vnet/dpo/dpo.h>
/**
* The BIER imposition object
*/
typedef struct bier_imp_t_ {
/**
* The BIER table into which to forward the post imposed packet
*/
bier_table_id_t bi_tbl;
/**
* number of locks
*/
u32 bi_locks;
/**
* The DPO contirubted from the resolving BIER table.
* One per-IP protocol. This allows us to share a BIER imposition
* object for a IPv4 and IPv6 mfib path.
*/
dpo_id_t bi_dpo[FIB_PROTOCOL_IP_MAX];
/**
* The Header to impose.
*/
bier_hdr_t bi_hdr;
/**
* The bit string.
* This is a memory v. speed tradeoff. We inline here the
* largest header type so as the bitstring is on the same
* cacheline as the header.
*/
bier_bit_mask_4096_t bi_bits;
} bier_imp_t;
extern index_t bier_imp_add_or_lock(const bier_table_id_t *bt,
bier_bp_t sender,
const bier_bit_string_t *bs);
extern void bier_imp_unlock(index_t bii);
extern void bier_imp_lock(index_t bii);
extern u8* format_bier_imp(u8* s, va_list *ap);
extern void bier_imp_contribute_forwarding(index_t bii,
dpo_proto_t proto,
dpo_id_t *dpo);
extern bier_imp_t *bier_imp_pool;
always_inline bier_imp_t*
bier_imp_get (index_t bii)
{
return (pool_elt_at_index(bier_imp_pool, bii));
}
#endif
+217
View File
@@ -0,0 +1,217 @@
/*
* 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/bier/bier_imp.h>
#include <vnet/bier/bier_hdr_inlines.h>
#include <vnet/ip/ip.h>
/**
* @brief A struct to hold tracing information for the BIER imposition
* node.
*/
typedef struct bier_imp_trace_t_
{
/**
* BIER imposition object hit
*/
index_t imp;
/**
* BIER hdr applied
*/
bier_hdr_t hdr;
} bier_imp_trace_t;
always_inline uword
bier_imp_dpo_inline (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * from_frame,
fib_protocol_t fproto,
bier_hdr_proto_id_t bproto)
{
u32 n_left_from, next_index, * from, * to_next;
from = vlib_frame_vector_args (from_frame);
n_left_from = from_frame->n_vectors;
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)
{
vlib_buffer_t * b0;
bier_imp_t *bimp0;
bier_hdr_t *hdr0;
u32 bi0, bii0;
u32 next0;
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);
bii0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
bimp0 = bier_imp_get(bii0);
if (FIB_PROTOCOL_IP4 == fproto)
{
/*
* decrement the TTL on ingress to the BIER domain
*/
ip4_header_t * ip0 = vlib_buffer_get_current(b0);
u32 checksum0;
checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
checksum0 += checksum0 >= 0xffff;
ip0->checksum = checksum0;
ip0->ttl -= 1;
/*
* calculate an entropy
*/
if (0 == vnet_buffer(b0)->ip.flow_hash)
{
vnet_buffer(b0)->ip.flow_hash =
ip4_compute_flow_hash (ip0, IP_FLOW_HASH_DEFAULT);
}
}
if (FIB_PROTOCOL_IP6 == fproto)
{
/*
* decrement the TTL on ingress to the BIER domain
*/
ip6_header_t * ip0 = vlib_buffer_get_current(b0);
ip0->hop_limit -= 1;
/*
* calculate an entropy
*/
if (0 == vnet_buffer(b0)->ip.flow_hash)
{
vnet_buffer(b0)->ip.flow_hash =
ip6_compute_flow_hash (ip0, IP_FLOW_HASH_DEFAULT);
}
}
/* Paint the BIER header */
vlib_buffer_advance(b0, -(sizeof(bier_hdr_t) +
bier_hdr_len_id_to_num_bytes(bimp0->bi_tbl.bti_hdr_len)));
hdr0 = vlib_buffer_get_current(b0);
clib_memcpy(hdr0, &bimp0->bi_hdr,
(sizeof(bier_hdr_t) +
bier_hdr_len_id_to_num_bytes(bimp0->bi_tbl.bti_hdr_len)));
/*
* Fixup the entropy and protocol, both of which have a
* zero value post the paint job
*/
hdr0->bh_oam_dscp_proto |=
clib_host_to_net_u16(bproto << BIER_HDR_PROTO_FIELD_SHIFT);
hdr0->bh_first_word |=
clib_host_to_net_u32((vnet_buffer(b0)->ip.flow_hash &
BIER_HDR_ENTROPY_FIELD_MASK) <<
BIER_HDR_ENTROPY_FIELD_SHIFT);
/* next node */
next0 = bimp0->bi_dpo[fproto].dpoi_next_node;
vnet_buffer(b0)->ip.adj_index[VLIB_TX] =
bimp0->bi_dpo[fproto].dpoi_index;
if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
{
bier_imp_trace_t *tr =
vlib_add_trace (vm, node, b0, sizeof (*tr));
tr->imp = bii0;
tr->hdr = *hdr0;
}
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);
}
return from_frame->n_vectors;
}
static u8 *
format_bier_imp_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_imp_trace_t * t;
u32 indent;
t = va_arg (*args, bier_imp_trace_t *);
indent = format_get_indent (s);
s = format (s, "%U", format_bier_imp, t->imp, indent, BIER_SHOW_BRIEF);
return (s);
}
static uword
bier_imp_ip4 (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
return (bier_imp_dpo_inline(vm, node, frame,
FIB_PROTOCOL_IP4,
BIER_HDR_PROTO_IPV4));
}
VLIB_REGISTER_NODE (bier_imp_ip4_node) = {
.function = bier_imp_ip4,
.name = "bier-imp-ip4",
.vector_size = sizeof (u32),
.format_trace = format_bier_imp_trace,
.n_next_nodes = 1,
.next_nodes = {
[0] = "error-drop",
}
};
VLIB_NODE_FUNCTION_MULTIARCH (bier_imp_ip4_node, bier_imp_ip4)
static uword
bier_imp_ip6 (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
return (bier_imp_dpo_inline(vm, node, frame,
FIB_PROTOCOL_IP6,
BIER_HDR_PROTO_IPV6));
}
VLIB_REGISTER_NODE (bier_imp_ip6_node) = {
.function = bier_imp_ip6,
.name = "bier-imp-ip6",
.vector_size = sizeof (u32),
.format_trace = format_bier_imp_trace,
.n_next_nodes = 1,
.next_nodes = {
[0] = "error-drop",
}
};
VLIB_NODE_FUNCTION_MULTIARCH (bier_imp_ip6_node, bier_imp_ip6)
+175
View File
@@ -0,0 +1,175 @@
/*
* 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_table.h>
#include <vnet/bier/bier_hdr_inlines.h>
typedef enum {
#define bier_error(n,s) BIER_INPUT_ERROR_##n,
#include <vnet/bier/bier_input_error.def>
#undef bier_error
BIER_INPUT_N_ERROR,
} bier_input_error_t;
static char * bier_error_strings[] = {
#define bier_error(n,s) s,
#include <vnet/bier/bier_input_error.def>
#undef bier_error
};
typedef enum bier_input_next_t_ {
BIER_INPUT_NEXT_BIER_LOOKUP,
BIER_INPUT_NEXT_DROP,
BIER_INPUT_N_NEXT,
} bier_input_next_t;
vlib_node_registration_t bier_input_node;
/**
* @brief Packet trace recoed for a BIER output
*/
typedef struct bier_input_trace_t_
{
u32 next_index;
u32 bt_index;
} bier_input_trace_t;
static int
bier_hdr_validate (bier_hdr_t *bier_hdr,
bier_hdr_len_id_t expected_length)
{
/*
* checks:
* - the version field must be 1
* - the header length matches the length expected
*/
if (PREDICT_FALSE((BIER_HDR_VERSION_1 != bier_hdr_get_version(bier_hdr)) ||
(expected_length != bier_hdr_get_len_id(bier_hdr)))) {
return (0);
}
return (1);
}
static uword
bier_input (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * from_frame)
{
u32 n_left_from, next_index, * from, * to_next;
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)
{
const bier_table_t *bt0;
vlib_buffer_t * b0;
bier_hdr_t * bh0;
u32 bi0, next0;
u32 bt_index0;
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_hdr_ntoh(bh0);
/*
* In the MPLS decap node we squirelled away the
* index for the BIER table as the tx adjacency
*/
bt_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
bt0 = bier_table_get(bt_index0);
if (PREDICT_TRUE(bier_hdr_validate(bh0, bt0->bt_id.bti_hdr_len)))
{
next0 = BIER_INPUT_NEXT_BIER_LOOKUP;
} else {
next0 = BIER_INPUT_NEXT_DROP;
b0->error = node->errors[BIER_INPUT_ERROR_INVALID_HEADER];
}
if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
{
bier_input_trace_t *tr;
tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
tr->next_index = next0;
tr->bt_index = bt_index0;
}
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_input_node.index,
BIER_INPUT_ERROR_PKTS_VALID,
from_frame->n_vectors);
return (from_frame->n_vectors);
}
static u8 *
format_bier_input_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_input_trace_t * t = va_arg (*args, bier_input_trace_t *);
s = format (s, " next [%d], BIER Table index %d",
t->next_index, t->bt_index);
return s;
}
VLIB_REGISTER_NODE (bier_input_node) = {
.function = bier_input,
.name = "bier-input",
/* Takes a vector of packets. */
.vector_size = sizeof (u32),
.n_errors = BIER_INPUT_N_ERROR,
.error_strings = bier_error_strings,
.n_next_nodes = BIER_INPUT_N_NEXT,
.next_nodes = {
[BIER_INPUT_NEXT_BIER_LOOKUP] = "bier-lookup",
[BIER_INPUT_NEXT_DROP] = "bier-drop",
},
.format_trace = format_bier_input_trace,
};
+19
View File
@@ -0,0 +1,19 @@
/*
* 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.
*/
bier_error (NONE, "no error")
bier_error (TABLE_NOT_FOUND, "table not found")
bier_error (INVALID_HEADER, "invalid header")
bier_error (PKTS_VALID, "BIER input packets")
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
/*
* 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.
*/
bier_error (NONE, "no error")
bier_error (FMASK_UNRES, "fmask unresolved")
bier_error (BUFFER_ALLOCATION_FAILURE, "Buffer Allocation Failure")
+195
View File
@@ -0,0 +1,195 @@
/*
* 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;
/**
* @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)
{
u32 n_left_from, next_index, * from, * to_next;
from = vlib_frame_vector_args (from_frame);
n_left_from = from_frame->n_vectors;
// vnet_buffer(b0)->sw_if_index[VLIB_TX] = d0->tx_fib_index;
/*
* 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;
bier_hdr_t *bh0;
u32 bi0, *h0;
u32 bfmi0;
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);
/*
* 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))
{
vlib_buffer_advance(b0, -(word)sizeof(mpls_label_t));
h0 = vlib_buffer_get_current(b0);
h0[0] = bfm0->bfm_label;
}
/*
* 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,
};
+17
View File
@@ -0,0 +1,17 @@
/*
* 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.
*/
bier_error (NONE, "no error")
bier_error (FMASK_UNRES, "fmask unresolved")
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More