Line data Source code
1 : /*
2 : * Copyright (c) 2015 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 : * ip/ip6_input.c: IP v6 input node
17 : *
18 : * Copyright (c) 2008 Eliot Dresselhaus
19 : *
20 : * Permission is hereby granted, free of charge, to any person obtaining
21 : * a copy of this software and associated documentation files (the
22 : * "Software"), to deal in the Software without restriction, including
23 : * without limitation the rights to use, copy, modify, merge, publish,
24 : * distribute, sublicense, and/or sell copies of the Software, and to
25 : * permit persons to whom the Software is furnished to do so, subject to
26 : * the following conditions:
27 : *
28 : * The above copyright notice and this permission notice shall be
29 : * included in all copies or substantial portions of the Software.
30 : *
31 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 : * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 : * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 : * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 : */
39 :
40 : #include <vnet/ip/ip6_input.h>
41 : #include <vnet/ethernet/ethernet.h>
42 : #include <vnet/ppp/ppp.h>
43 : #include <vnet/hdlc/hdlc.h>
44 : #include <vnet/pg/pg.h>
45 :
46 : typedef struct
47 : {
48 : u8 packet_data[64];
49 : } ip6_input_trace_t;
50 :
51 : static u8 *
52 156654 : format_ip6_input_trace (u8 * s, va_list * va)
53 : {
54 156654 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
55 156654 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
56 156654 : ip6_input_trace_t *t = va_arg (*va, ip6_input_trace_t *);
57 :
58 156654 : s = format (s, "%U",
59 156654 : format_ip6_header, t->packet_data, sizeof (t->packet_data));
60 :
61 156654 : return s;
62 : }
63 :
64 : /* Validate IP v6 packets and pass them either to forwarding code
65 : or drop exception packets. */
66 235081 : VLIB_NODE_FN (ip6_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
67 : vlib_frame_t * frame)
68 : {
69 232781 : vnet_main_t *vnm = vnet_get_main ();
70 232781 : ip6_main_t *im = &ip6_main;
71 232781 : ip_lookup_main_t *lm = &im->lookup_main;
72 : u32 n_left_from, *from, *to_next;
73 : ip6_input_next_t next_index;
74 : vlib_node_runtime_t *error_node =
75 232781 : vlib_node_get_runtime (vm, ip6_input_node.index);
76 : vlib_simple_counter_main_t *cm;
77 232781 : u32 thread_index = vm->thread_index;
78 :
79 232781 : from = vlib_frame_vector_args (frame);
80 232781 : n_left_from = frame->n_vectors;
81 232781 : next_index = node->cached_next_index;
82 :
83 232781 : if (node->flags & VLIB_NODE_FLAG_TRACE)
84 5466 : vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
85 : /* stride */ 1,
86 : sizeof (ip6_input_trace_t));
87 :
88 232782 : cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
89 : VNET_INTERFACE_COUNTER_IP6);
90 :
91 465565 : while (n_left_from > 0)
92 : {
93 : u32 n_left_to_next;
94 :
95 232784 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
96 :
97 4997010 : while (n_left_from >= 4 && n_left_to_next >= 2)
98 : {
99 : vlib_buffer_t *p0, *p1;
100 : ip6_header_t *ip0, *ip1;
101 4764220 : u32 pi0, sw_if_index0, next0 = 0;
102 4764220 : u32 pi1, sw_if_index1, next1 = 0;
103 : u8 arc0, arc1;
104 :
105 : /* Prefetch next iteration. */
106 : {
107 : vlib_buffer_t *p2, *p3;
108 :
109 4764220 : p2 = vlib_get_buffer (vm, from[2]);
110 4764220 : p3 = vlib_get_buffer (vm, from[3]);
111 :
112 4764220 : vlib_prefetch_buffer_header (p2, LOAD);
113 4764220 : vlib_prefetch_buffer_header (p3, LOAD);
114 :
115 4764220 : CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
116 4764220 : CLIB_PREFETCH (p3->data, sizeof (ip1[0]), LOAD);
117 : }
118 :
119 4764220 : pi0 = from[0];
120 4764220 : pi1 = from[1];
121 :
122 4764220 : to_next[0] = pi0;
123 4764220 : to_next[1] = pi1;
124 4764220 : from += 2;
125 4764220 : to_next += 2;
126 4764220 : n_left_from -= 2;
127 4764220 : n_left_to_next -= 2;
128 :
129 4764220 : p0 = vlib_get_buffer (vm, pi0);
130 4764220 : p1 = vlib_get_buffer (vm, pi1);
131 :
132 4764220 : ip0 = vlib_buffer_get_current (p0);
133 4764220 : ip1 = vlib_buffer_get_current (p1);
134 :
135 4764220 : sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
136 4764220 : sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
137 :
138 4764220 : if (PREDICT_FALSE (ip6_address_is_multicast (&ip0->dst_address)))
139 : {
140 480 : arc0 = lm->mcast_feature_arc_index;
141 480 : next0 = IP6_INPUT_NEXT_LOOKUP_MULTICAST;
142 : }
143 : else
144 : {
145 4763740 : arc0 = lm->ucast_feature_arc_index;
146 4763740 : next0 = IP6_INPUT_NEXT_LOOKUP;
147 : }
148 :
149 4764220 : if (PREDICT_FALSE (ip6_address_is_multicast (&ip1->dst_address)))
150 : {
151 468 : arc1 = lm->mcast_feature_arc_index;
152 468 : next1 = IP6_INPUT_NEXT_LOOKUP_MULTICAST;
153 : }
154 : else
155 : {
156 4763750 : arc1 = lm->ucast_feature_arc_index;
157 4763750 : next1 = IP6_INPUT_NEXT_LOOKUP;
158 : }
159 :
160 4764220 : vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
161 4764220 : vnet_buffer (p1)->ip.adj_index[VLIB_RX] = ~0;
162 :
163 4764220 : vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0);
164 4764220 : vnet_feature_arc_start (arc1, sw_if_index1, &next1, p1);
165 :
166 4764220 : vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1);
167 4764220 : vlib_increment_simple_counter (cm, thread_index, sw_if_index1, 1);
168 4764220 : ip6_input_check_x2 (vm, error_node,
169 : p0, p1, ip0, ip1, &next0, &next1);
170 :
171 4764220 : vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
172 : to_next, n_left_to_next,
173 : pi0, pi1, next0, next1);
174 : }
175 :
176 747288 : while (n_left_from > 0 && n_left_to_next > 0)
177 : {
178 : vlib_buffer_t *p0;
179 : ip6_header_t *ip0;
180 514504 : u32 pi0, sw_if_index0, next0 = 0;
181 : u8 arc0;
182 :
183 514504 : pi0 = from[0];
184 514504 : to_next[0] = pi0;
185 514504 : from += 1;
186 514504 : to_next += 1;
187 514504 : n_left_from -= 1;
188 514504 : n_left_to_next -= 1;
189 :
190 514504 : p0 = vlib_get_buffer (vm, pi0);
191 514504 : ip0 = vlib_buffer_get_current (p0);
192 :
193 514504 : sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
194 514504 : if (PREDICT_FALSE (ip6_address_is_multicast (&ip0->dst_address)))
195 : {
196 3109 : arc0 = lm->mcast_feature_arc_index;
197 3109 : next0 = IP6_INPUT_NEXT_LOOKUP_MULTICAST;
198 : }
199 : else
200 : {
201 511395 : arc0 = lm->ucast_feature_arc_index;
202 511395 : next0 = IP6_INPUT_NEXT_LOOKUP;
203 : }
204 :
205 514504 : vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
206 514504 : vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0);
207 :
208 514504 : vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1);
209 514504 : ip6_input_check_x1 (vm, error_node, p0, ip0, &next0);
210 :
211 514504 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
212 : to_next, n_left_to_next,
213 : pi0, next0);
214 : }
215 :
216 232784 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
217 : }
218 :
219 232781 : return frame->n_vectors;
220 : }
221 :
222 : /* *INDENT-OFF* */
223 183788 : VLIB_REGISTER_NODE (ip6_input_node) = {
224 : .name = "ip6-input",
225 : .vector_size = sizeof (u32),
226 :
227 : .n_errors = IP6_N_ERROR,
228 : .error_counters = ip6_error_counters,
229 :
230 : .n_next_nodes = IP6_INPUT_N_NEXT,
231 : .next_nodes = {
232 : [IP6_INPUT_NEXT_DROP] = "error-drop",
233 : [IP6_INPUT_NEXT_LOOKUP] = "ip6-lookup",
234 : [IP6_INPUT_NEXT_ICMP_ERROR] = "ip6-icmp-error",
235 : [IP6_INPUT_NEXT_LOOKUP_MULTICAST] = "ip6-mfib-forward-lookup",
236 : },
237 :
238 : .format_buffer = format_ip6_header,
239 : .format_trace = format_ip6_input_trace,
240 : };
241 : /* *INDENT-ON* */
242 :
243 : static clib_error_t *
244 575 : ip6_init (vlib_main_t * vm)
245 : {
246 575 : ethernet_register_input_type (vm, ETHERNET_TYPE_IP6, ip6_input_node.index);
247 575 : ppp_register_input_protocol (vm, PPP_PROTOCOL_ip6, ip6_input_node.index);
248 575 : hdlc_register_input_protocol (vm, HDLC_PROTOCOL_ip6, ip6_input_node.index);
249 :
250 : {
251 : pg_node_t *pn;
252 575 : pn = pg_get_node (ip6_input_node.index);
253 575 : pn->unformat_edit = unformat_pg_ip6_header;
254 : }
255 :
256 : /* Set flow hash to something non-zero. */
257 575 : ip6_main.flow_hash_seed = 0xdeadbeef;
258 :
259 : /* Default hop limit for packets we generate. */
260 575 : ip6_main.host_config.ttl = 64;
261 :
262 :
263 575 : uword *u = hash_get (ip_main.protocol_info_by_name, "IPV6_FRAGMENTATION");
264 575 : if (u)
265 : {
266 575 : ip_protocol_info_t *info =
267 575 : vec_elt_at_index (ip_main.protocol_infos, *u);
268 575 : ASSERT (NULL == info->format_header);
269 575 : info->format_header = format_ip6_frag_hdr;
270 : }
271 575 : return /* no error */ 0;
272 : }
273 :
274 14975 : VLIB_INIT_FUNCTION (ip6_init);
275 :
276 : /*
277 : * fd.io coding-style-patch-verification: ON
278 : *
279 : * Local Variables:
280 : * eval: (c-set-style "gnu")
281 : * End:
282 : */
|