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/bier/bier_imp.h>
17 : #include <vnet/bier/bier_hdr_inlines.h>
18 : #include <vnet/ip/ip4_inlines.h>
19 : #include <vnet/ip/ip6_inlines.h>
20 :
21 : /**
22 : * @brief A struct to hold tracing information for the BIER imposition
23 : * node.
24 : */
25 : typedef struct bier_imp_trace_t_
26 : {
27 : /**
28 : * BIER imposition object hit
29 : */
30 : index_t imp;
31 :
32 : /**
33 : * BIER hdr applied
34 : */
35 : bier_hdr_t hdr;
36 : } bier_imp_trace_t;
37 :
38 : always_inline uword
39 5 : bier_imp_dpo_inline (vlib_main_t * vm,
40 : vlib_node_runtime_t * node,
41 : vlib_frame_t * from_frame,
42 : fib_protocol_t fproto,
43 : bier_hdr_proto_id_t bproto)
44 : {
45 : u32 n_left_from, next_index, * from, * to_next;
46 :
47 5 : from = vlib_frame_vector_args (from_frame);
48 5 : n_left_from = from_frame->n_vectors;
49 :
50 5 : next_index = node->cached_next_index;
51 :
52 10 : while (n_left_from > 0)
53 : {
54 : u32 n_left_to_next;
55 :
56 5 : vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
57 :
58 142 : while (n_left_from > 0 && n_left_to_next > 0)
59 : {
60 : vlib_buffer_t * b0;
61 : bier_imp_t *bimp0;
62 : bier_hdr_t *hdr0;
63 : u32 bi0, bii0;
64 : u32 next0;
65 :
66 137 : bi0 = from[0];
67 137 : to_next[0] = bi0;
68 137 : from += 1;
69 137 : to_next += 1;
70 137 : n_left_from -= 1;
71 137 : n_left_to_next -= 1;
72 :
73 137 : b0 = vlib_get_buffer (vm, bi0);
74 :
75 137 : bii0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
76 137 : bimp0 = bier_imp_get(bii0);
77 :
78 137 : if (FIB_PROTOCOL_IP4 == fproto)
79 : {
80 : /*
81 : * decrement the TTL on ingress to the BIER domain
82 : */
83 137 : ip4_header_t * ip0 = vlib_buffer_get_current(b0);
84 : u32 checksum0;
85 :
86 137 : checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
87 137 : checksum0 += checksum0 >= 0xffff;
88 :
89 137 : ip0->checksum = checksum0;
90 137 : ip0->ttl -= 1;
91 :
92 : /*
93 : * calculate an entropy
94 : */
95 137 : if (0 == vnet_buffer(b0)->ip.flow_hash)
96 : {
97 137 : vnet_buffer(b0)->ip.flow_hash =
98 137 : ip4_compute_flow_hash (ip0, IP_FLOW_HASH_DEFAULT);
99 : }
100 : }
101 137 : if (FIB_PROTOCOL_IP6 == fproto)
102 : {
103 : /*
104 : * decrement the TTL on ingress to the BIER domain
105 : */
106 0 : ip6_header_t * ip0 = vlib_buffer_get_current(b0);
107 :
108 0 : ip0->hop_limit -= 1;
109 :
110 : /*
111 : * calculate an entropy
112 : */
113 0 : if (0 == vnet_buffer(b0)->ip.flow_hash)
114 : {
115 0 : vnet_buffer(b0)->ip.flow_hash =
116 0 : ip6_compute_flow_hash (ip0, IP_FLOW_HASH_DEFAULT);
117 : }
118 : }
119 :
120 : /* Paint the BIER header */
121 137 : vlib_buffer_advance(b0, -(sizeof(bier_hdr_t) +
122 137 : bier_hdr_len_id_to_num_bytes(bimp0->bi_tbl.bti_hdr_len)));
123 137 : hdr0 = vlib_buffer_get_current(b0);
124 :
125 : /* RPF check */
126 137 : if (PREDICT_FALSE(BIER_RX_ITF == vnet_buffer(b0)->ip.adj_index[VLIB_RX]))
127 : {
128 1 : next0 = 0;
129 : }
130 : else
131 : {
132 136 : clib_memcpy_fast(hdr0, &bimp0->bi_hdr,
133 : (sizeof(bier_hdr_t) +
134 136 : bier_hdr_len_id_to_num_bytes(bimp0->bi_tbl.bti_hdr_len)));
135 : /*
136 : * Fixup the entropy and protocol, both of which have a
137 : * zero value post the paint job
138 : */
139 136 : hdr0->bh_oam_dscp_proto |=
140 136 : clib_host_to_net_u16(bproto << BIER_HDR_PROTO_FIELD_SHIFT);
141 136 : hdr0->bh_first_word |=
142 136 : clib_host_to_net_u32((vnet_buffer(b0)->ip.flow_hash &
143 : BIER_HDR_ENTROPY_FIELD_MASK) <<
144 : BIER_HDR_ENTROPY_FIELD_SHIFT);
145 :
146 : /*
147 : * use TTL 64 for the post encap MPLS label/BIFT-ID
148 : * this we be decremented in bier_output node.
149 : */
150 136 : vnet_buffer(b0)->mpls.ttl = 65;
151 :
152 : /* next node */
153 136 : next0 = bimp0->bi_dpo[fproto].dpoi_next_node;
154 136 : vnet_buffer(b0)->ip.adj_index[VLIB_TX] =
155 136 : bimp0->bi_dpo[fproto].dpoi_index;
156 : }
157 :
158 137 : if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
159 : {
160 : bier_imp_trace_t *tr =
161 137 : vlib_add_trace (vm, node, b0, sizeof (*tr));
162 137 : tr->imp = bii0;
163 137 : tr->hdr = *hdr0;
164 : }
165 :
166 137 : vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
167 : n_left_to_next, bi0, next0);
168 : }
169 5 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
170 : }
171 5 : return from_frame->n_vectors;
172 : }
173 :
174 : static u8 *
175 171 : format_bier_imp_trace (u8 * s, va_list * args)
176 : {
177 171 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
178 171 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
179 : bier_imp_trace_t * t;
180 : u32 indent;
181 :
182 171 : t = va_arg (*args, bier_imp_trace_t *);
183 171 : indent = format_get_indent (s);
184 :
185 171 : s = format (s, "%U", format_bier_imp, t->imp, indent, BIER_SHOW_BRIEF);
186 171 : return (s);
187 : }
188 :
189 2241 : VLIB_NODE_FN (bier_imp_ip4_node) (vlib_main_t * vm,
190 : vlib_node_runtime_t * node,
191 : vlib_frame_t * frame)
192 : {
193 5 : return (bier_imp_dpo_inline(vm, node, frame,
194 : FIB_PROTOCOL_IP4,
195 : BIER_HDR_PROTO_IPV4));
196 : }
197 :
198 178120 : VLIB_REGISTER_NODE (bier_imp_ip4_node) = {
199 : .name = "bier-imp-ip4",
200 : .vector_size = sizeof (u32),
201 :
202 : .format_trace = format_bier_imp_trace,
203 : .n_next_nodes = 1,
204 : .next_nodes = {
205 : [0] = "bier-drop",
206 : }
207 : };
208 :
209 2236 : VLIB_NODE_FN (bier_imp_ip6_node) (vlib_main_t * vm,
210 : vlib_node_runtime_t * node,
211 : vlib_frame_t * frame)
212 : {
213 0 : return (bier_imp_dpo_inline(vm, node, frame,
214 : FIB_PROTOCOL_IP6,
215 : BIER_HDR_PROTO_IPV6));
216 : }
217 :
218 178120 : VLIB_REGISTER_NODE (bier_imp_ip6_node) = {
219 : .name = "bier-imp-ip6",
220 : .vector_size = sizeof (u32),
221 :
222 : .format_trace = format_bier_imp_trace,
223 : .n_next_nodes = 1,
224 : .next_nodes = {
225 : [0] = "error-drop",
226 : }
227 : };
|