Line data Source code
1 : /*
2 : * Copyright (c) 2016 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 :
16 : #include <vnet/buffer.h>
17 :
18 : #include <vnet/bier/bier_fmask.h>
19 : #include <vnet/bier/bier_hdr_inlines.h>
20 : #include <vlib/vlib.h>
21 :
22 : static char * bier_output_error_strings[] = {
23 : #define bier_error(n,s) s,
24 : #include <vnet/bier/bier_output_error.def>
25 : #undef bier_error
26 : };
27 :
28 : /*
29 : * Keep these values semantically the same as BIER output
30 : */
31 : #define foreach_bier_output_next \
32 : _(DROP, "bier-drop")
33 :
34 : typedef enum {
35 : #define _(s,n) BIER_OUTPUT_NEXT_##s,
36 : foreach_bier_output_next
37 : #undef _
38 : BIER_OUTPUT_N_NEXT,
39 : } bier_output_next_t;
40 :
41 : typedef enum {
42 : #define bier_error(n,s) BIER_OUTPUT_ERROR_##n,
43 : #include <vnet/bier/bier_output_error.def>
44 : #undef bier_error
45 : BIER_OUTPUT_N_ERROR,
46 : } bier_output_error_t;
47 :
48 : /**
49 : * Forward declaration
50 : */
51 : vlib_node_registration_t bier_output_node;
52 : extern vlib_combined_counter_main_t bier_fmask_counters;
53 :
54 : /**
55 : * @brief Packet trace record for a BIER output
56 : */
57 : typedef struct bier_output_trace_t_
58 : {
59 : u32 next_index;
60 : index_t bfm_index;
61 : mpls_label_t bfm_label;
62 : } bier_output_trace_t;
63 :
64 : static uword
65 17 : bier_output (vlib_main_t * vm,
66 : vlib_node_runtime_t * node,
67 : vlib_frame_t * from_frame)
68 : {
69 17 : vlib_combined_counter_main_t *cm = &bier_fmask_counters;
70 : u32 n_left_from, next_index, * from, * to_next;
71 : u32 thread_index;
72 :
73 17 : thread_index = vm->thread_index;
74 17 : from = vlib_frame_vector_args (from_frame);
75 17 : n_left_from = from_frame->n_vectors;
76 :
77 : /*
78 : * objection your honour! speculation!
79 : */
80 17 : next_index = node->cached_next_index;
81 :
82 34 : while (n_left_from > 0)
83 : {
84 : u32 n_left_to_next;
85 :
86 17 : vlib_get_next_frame (vm, node, next_index,
87 : to_next, n_left_to_next);
88 :
89 1059 : while (n_left_from > 0 && n_left_to_next > 0)
90 : {
91 : bier_output_next_t next0;
92 : bier_bit_string_t bbs;
93 : vlib_buffer_t * b0;
94 : bier_fmask_t *bfm0;
95 : mpls_label_t *h0;
96 : bier_hdr_t *bh0;
97 : u32 bfmi0;
98 : u32 bi0;
99 :
100 1042 : bi0 = from[0];
101 1042 : to_next[0] = bi0;
102 1042 : from += 1;
103 1042 : to_next += 1;
104 1042 : n_left_from -= 1;
105 1042 : n_left_to_next -= 1;
106 :
107 1042 : b0 = vlib_get_buffer (vm, bi0);
108 1042 : bh0 = vlib_buffer_get_current (b0);
109 1042 : bier_bit_string_init_from_hdr(bh0, &bbs);
110 :
111 : /*
112 : * In the BIER Lookup node we squirrelled away the
113 : * BIER fmask index as the adj index
114 : */
115 1042 : bfmi0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
116 1042 : bfm0 = bier_fmask_get(bfmi0);
117 :
118 1042 : vlib_increment_combined_counter(
119 : cm, thread_index, bfmi0, 1,
120 : vlib_buffer_length_in_chain (vm, b0));
121 :
122 : /*
123 : * perform the logical AND of the packet's mask with
124 : * that of the fmask objects, to reset the bits that
125 : * are only on the shortest path the the fmask NH.
126 : */
127 1042 : bier_bit_string_logical_and_string(
128 1042 : &bfm0->bfm_bits.bfmb_input_reset_string,
129 : &bbs);
130 :
131 : /*
132 : * this is the last time we touch the BIER header
133 : * so flip to network order
134 : */
135 1042 : bier_hdr_hton(bh0);
136 :
137 : /*
138 : * paint the BIER peer's label
139 : */
140 1042 : if (!(bfm0->bfm_flags & BIER_FMASK_FLAG_DISP))
141 : {
142 : /*
143 : * since a BIFT value and a MPLS label are formated the
144 : * same, this painting works OK.
145 : */
146 902 : vlib_buffer_advance(b0, -(word)sizeof(mpls_label_t));
147 902 : h0 = vlib_buffer_get_current(b0);
148 :
149 902 : h0[0] = bfm0->bfm_label;
150 :
151 902 : ((char*)h0)[3]= vnet_buffer(b0)->mpls.ttl - 1;
152 : }
153 :
154 : /*
155 : * setup next graph node
156 : */
157 1042 : next0 = bfm0->bfm_dpo.dpoi_next_node;
158 1042 : vnet_buffer(b0)->ip.adj_index[VLIB_TX] = bfm0->bfm_dpo.dpoi_index;
159 :
160 1042 : if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
161 : {
162 : bier_output_trace_t *tr;
163 :
164 1042 : tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
165 1042 : tr->next_index = next0;
166 1042 : tr->bfm_index = bfmi0;
167 1042 : tr->bfm_label = bfm0->bfm_label;
168 : }
169 :
170 1042 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
171 : to_next, n_left_to_next,
172 : bi0, next0);
173 : }
174 :
175 17 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
176 : }
177 :
178 17 : vlib_node_increment_counter (vm, bier_output_node.index,
179 : BIER_OUTPUT_ERROR_NONE,
180 17 : from_frame->n_vectors);
181 17 : return (from_frame->n_vectors);
182 : }
183 :
184 : static u8 *
185 392 : format_bier_output_trace (u8 * s, va_list * args)
186 : {
187 392 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
188 392 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
189 392 : bier_output_trace_t * t = va_arg (*args, bier_output_trace_t *);
190 :
191 392 : s = format (s, " next [%d], BFM index %d label:%x",
192 : t->next_index, t->bfm_index, t->bfm_label);
193 392 : return s;
194 : }
195 :
196 178120 : VLIB_REGISTER_NODE (bier_output_node) = {
197 : .function = bier_output,
198 : .name = "bier-output",
199 : /* Takes a vector of packets. */
200 : .vector_size = sizeof (u32),
201 :
202 : .n_errors = BIER_OUTPUT_N_ERROR,
203 : .error_strings = bier_output_error_strings,
204 :
205 : .n_next_nodes = BIER_OUTPUT_N_NEXT,
206 : .next_nodes = {
207 : [BIER_OUTPUT_NEXT_DROP] = "bier-drop",
208 : },
209 :
210 : .format_trace = format_bier_output_trace,
211 : };
|