Line data Source code
1 : /*
2 : *------------------------------------------------------------------
3 : * ip_path_mtu.c
4 : *
5 : * Copyright (c) 2020 Graphiant.
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at:
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : *------------------------------------------------------------------
18 : */
19 :
20 : #include <vnet/ip/ip_path_mtu.h>
21 : #include <vnet/ip/ip_frag.h>
22 :
23 : typedef enum
24 : {
25 : IP_PMTU_DROP,
26 : IP_PMTU_N_NEXT,
27 : } ip_pmtu_next_t;
28 :
29 : typedef struct ip_pmtu_trace_t_
30 : {
31 : u16 pmtu;
32 : u16 packet_size;
33 : } ip_pmtu_trace_t;
34 :
35 : static u8 *
36 6 : format_ip_pmtu_trace (u8 *s, va_list *args)
37 : {
38 6 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
39 6 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
40 6 : ip_pmtu_trace_t *t = va_arg (*args, ip_pmtu_trace_t *);
41 :
42 6 : s = format (s, "path mtu:%d packet size:%d", t->pmtu, t->packet_size);
43 :
44 6 : return s;
45 : }
46 :
47 : static inline uword
48 6 : ip_pmtu_dpo_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
49 : vlib_frame_t *frame, ip_address_family_t af)
50 : {
51 : u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
52 :
53 6 : from = vlib_frame_vector_args (frame);
54 6 : n_left_from = frame->n_vectors;
55 6 : next_index = node->cached_next_index;
56 :
57 6 : u32 *buffer = 0;
58 :
59 12 : while (n_left_from > 0)
60 : {
61 6 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
62 :
63 12 : while (n_left_from > 0 && n_left_to_next > 0)
64 : {
65 : const ip_pmtu_dpo_t *ipm0;
66 : u32 pi0, *frag_from, frag_left;
67 : vlib_buffer_t *p0;
68 : ip_frag_error_t error0;
69 : u16 next0;
70 :
71 : /*
72 : * Note: The packet is not enqueued now. It is instead put
73 : * in a vector where other fragments will be put as well.
74 : */
75 6 : pi0 = from[0];
76 6 : from += 1;
77 6 : n_left_from -= 1;
78 :
79 6 : p0 = vlib_get_buffer (vm, pi0);
80 6 : ipm0 = ip_pmtu_dpo_get (vnet_buffer (p0)->ip.adj_index[VLIB_TX]);
81 6 : vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ipm0->ipm_dpo.dpoi_index;
82 6 : next0 = ipm0->ipm_dpo.dpoi_next_node;
83 :
84 6 : if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
85 : {
86 : ip_pmtu_trace_t *t;
87 6 : t = vlib_add_trace (vm, node, p0, sizeof (*t));
88 6 : t->pmtu = ipm0->ipm_pmtu;
89 6 : t->packet_size = vlib_buffer_length_in_chain (vm, p0);
90 : }
91 :
92 6 : if (AF_IP6 == af)
93 : error0 =
94 6 : ip6_frag_do_fragment (vm, pi0, ipm0->ipm_pmtu, 0, &buffer);
95 : else
96 : error0 =
97 0 : ip4_frag_do_fragment (vm, pi0, ipm0->ipm_pmtu, 0, &buffer);
98 :
99 6 : if (AF_IP4 == af && error0 == IP_FRAG_ERROR_DONT_FRAGMENT_SET)
100 : {
101 0 : icmp4_error_set_vnet_buffer (
102 : p0, ICMP4_destination_unreachable,
103 : ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
104 0 : ipm0->ipm_pmtu);
105 0 : next0 = IP_FRAG_NEXT_ICMP_ERROR;
106 : }
107 : else
108 : {
109 6 : next0 =
110 : (error0 == IP_FRAG_ERROR_NONE ? next0 : IP_FRAG_NEXT_DROP);
111 : }
112 :
113 6 : if (error0 == IP_FRAG_ERROR_NONE)
114 : {
115 : /* Free original buffer chain */
116 6 : vlib_buffer_free_one (vm, pi0); /* Free original packet */
117 : }
118 : else
119 : {
120 0 : vlib_error_count (vm, node->node_index, error0, 1);
121 0 : vec_add1 (buffer, pi0); /* Get rid of the original buffer */
122 : }
123 :
124 : /* Send fragments that were added in the frame */
125 6 : frag_from = buffer;
126 6 : frag_left = vec_len (buffer);
127 :
128 12 : while (frag_left > 0)
129 : {
130 21 : while (frag_left > 0 && n_left_to_next > 0)
131 : {
132 : u32 i;
133 15 : i = to_next[0] = frag_from[0];
134 15 : frag_from += 1;
135 15 : frag_left -= 1;
136 15 : to_next += 1;
137 15 : n_left_to_next -= 1;
138 :
139 15 : vlib_get_buffer (vm, i)->error = node->errors[error0];
140 15 : vlib_validate_buffer_enqueue_x1 (
141 : vm, node, next_index, to_next, n_left_to_next, i, next0);
142 : }
143 6 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
144 6 : vlib_get_next_frame (vm, node, next_index, to_next,
145 : n_left_to_next);
146 : }
147 6 : vec_reset_length (buffer);
148 : }
149 6 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
150 : }
151 6 : vec_free (buffer);
152 :
153 6 : return frame->n_vectors;
154 : }
155 :
156 : // clang-format off
157 :
158 2300 : VLIB_NODE_FN (ip4_ip_pmtu_dpo_node) (vlib_main_t *vm,
159 : vlib_node_runtime_t *node,
160 : vlib_frame_t *from_frame)
161 : {
162 0 : return (ip_pmtu_dpo_inline (vm, node, from_frame, 0));
163 : }
164 :
165 2306 : VLIB_NODE_FN (ip6_ip_pmtu_dpo_node) (vlib_main_t *vm,
166 : vlib_node_runtime_t *node,
167 : vlib_frame_t *from_frame)
168 : {
169 6 : return (ip_pmtu_dpo_inline (vm, node, from_frame, 1));
170 : }
171 :
172 183788 : VLIB_REGISTER_NODE (ip4_ip_pmtu_dpo_node) = {
173 : .name = "ip4-pmtu-dpo",
174 : .vector_size = sizeof (u32),
175 : .format_trace = format_ip_pmtu_trace,
176 : .n_errors = IP_FRAG_N_ERROR,
177 : .error_counters = ip_frag_error_counters,
178 : .n_next_nodes = IP_PMTU_N_NEXT,
179 : .next_nodes =
180 : {
181 : [IP_PMTU_DROP] = "ip4-drop",
182 : }
183 : };
184 183788 : VLIB_REGISTER_NODE (ip6_ip_pmtu_dpo_node) = {
185 : .name = "ip6-pmtu-dpo",
186 : .vector_size = sizeof (u32),
187 : .format_trace = format_ip_pmtu_trace,
188 : .n_errors = IP_FRAG_N_ERROR,
189 : .error_counters = ip_frag_error_counters,
190 : .n_next_nodes = IP_PMTU_N_NEXT,
191 : .next_nodes =
192 : {
193 : [IP_PMTU_DROP] = "ip6-drop",
194 : }
195 : };
196 :
197 : // clang-format on
198 :
199 : /*
200 : * fd.io coding-style-patch-verification: ON
201 : *
202 : * Local Variables:
203 : * eval: (c-set-style "gnu")
204 : * End:
205 : */
|