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 : #include <vnet/ip/ip.h>
17 : #include <vnet/ip/ip_punt_drop.h>
18 : #include <vnet/fib/fib_path_list.h>
19 :
20 : ip_punt_redirect_cfg_t ip_punt_redirect_cfg;
21 :
22 : u8 *
23 5118 : format_ip_punt_redirect_trace (u8 * s, va_list * args)
24 : {
25 5118 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
26 5118 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
27 5118 : ip_punt_redirect_trace_t *t = va_arg (*args, ip_punt_redirect_trace_t *);
28 :
29 5118 : if (INDEX_INVALID == t->rrxi)
30 0 : s = format (s, "ignore");
31 : else
32 5118 : s = format (s, "via redirect:%d", t->rrxi);
33 :
34 5118 : return s;
35 : }
36 :
37 : static void
38 96 : ip_punt_redirect_stack (ip_punt_redirect_rx_t * ipr)
39 : {
40 96 : dpo_id_t dpo = DPO_INVALID;
41 : vlib_node_t *pnode;
42 :
43 96 : fib_path_list_contribute_forwarding (ipr->pl,
44 96 : ipr->payload_type,
45 : FIB_PATH_LIST_FWD_FLAG_COLLAPSE, &dpo);
46 :
47 96 : if (FIB_PROTOCOL_IP4 == ipr->fproto)
48 : pnode =
49 49 : vlib_get_node_by_name (vlib_get_main (), (u8 *) "ip4-punt-redirect");
50 : else
51 : pnode =
52 47 : vlib_get_node_by_name (vlib_get_main (), (u8 *) "ip6-punt-redirect");
53 :
54 96 : dpo_stack_from_node (pnode->index, &ipr->dpo, &dpo);
55 96 : dpo_reset (&dpo);
56 96 : }
57 :
58 : index_t
59 50 : ip_punt_redirect_find (fib_protocol_t fproto, u32 rx_sw_if_index)
60 : {
61 : index_t *rxs;
62 :
63 50 : rxs = ip_punt_redirect_cfg.redirect_by_rx_sw_if_index[fproto];
64 :
65 50 : if (vec_len (rxs) <= rx_sw_if_index)
66 0 : return (INDEX_INVALID);
67 :
68 50 : return rxs[rx_sw_if_index];
69 : }
70 :
71 : void
72 39 : ip_punt_redirect_add (fib_protocol_t fproto, u32 rx_sw_if_index,
73 : fib_forward_chain_type_t ct,
74 : const fib_route_path_t *rpaths)
75 : {
76 : ip_punt_redirect_rx_t *ipr;
77 : index_t ipri;
78 :
79 39 : if (~0 == rx_sw_if_index)
80 3 : rx_sw_if_index = 0;
81 :
82 107 : vec_validate_init_empty (ip_punt_redirect_cfg.redirect_by_rx_sw_if_index
83 : [fproto], rx_sw_if_index, INDEX_INVALID);
84 :
85 39 : pool_get (ip_punt_redirect_cfg.pool, ipr);
86 39 : ipri = ipr - ip_punt_redirect_cfg.pool;
87 :
88 39 : ip_punt_redirect_cfg.redirect_by_rx_sw_if_index[fproto][rx_sw_if_index] =
89 : ipri;
90 :
91 39 : fib_node_init (&ipr->node, FIB_NODE_TYPE_IP_PUNT_REDIRECT);
92 39 : ipr->fproto = fproto;
93 39 : ipr->payload_type = ct;
94 :
95 39 : ipr->pl = fib_path_list_create (FIB_PATH_LIST_FLAG_NO_URPF, rpaths);
96 :
97 39 : ipr->sibling = fib_path_list_child_add (ipr->pl,
98 : FIB_NODE_TYPE_IP_PUNT_REDIRECT,
99 : ipri);
100 :
101 39 : ip_punt_redirect_stack (ipr);
102 39 : }
103 :
104 : void
105 37 : ip_punt_redirect_del (fib_protocol_t fproto, u32 rx_sw_if_index)
106 : {
107 : ip_punt_redirect_rx_t *ipr;
108 : index_t *rxs;
109 :
110 37 : if (~0 == rx_sw_if_index)
111 3 : rx_sw_if_index = 0;
112 :
113 37 : rxs = ip_punt_redirect_cfg.redirect_by_rx_sw_if_index[fproto];
114 :
115 37 : if ((vec_len (rxs) <= rx_sw_if_index) ||
116 37 : (INDEX_INVALID == rxs[rx_sw_if_index]))
117 0 : return;
118 :
119 37 : ipr = ip_punt_redirect_get (rxs[rx_sw_if_index]);
120 :
121 37 : fib_path_list_child_remove (ipr->pl, ipr->sibling);
122 37 : dpo_reset (&ipr->dpo);
123 37 : pool_put (ip_punt_redirect_cfg.pool, ipr);
124 :
125 37 : rxs[rx_sw_if_index] = INDEX_INVALID;
126 : }
127 :
128 : u8 *
129 2 : format_ip_punt_redirect (u8 * s, va_list * args)
130 : {
131 2 : fib_protocol_t fproto = va_arg (*args, int);
132 : ip_punt_redirect_rx_t *rx;
133 : index_t *rxs;
134 : u32 rx_sw_if_index;
135 2 : vnet_main_t *vnm = vnet_get_main ();
136 :
137 2 : rxs = ip_punt_redirect_cfg.redirect_by_rx_sw_if_index[fproto];
138 :
139 18 : vec_foreach_index (rx_sw_if_index, rxs)
140 : {
141 16 : if (INDEX_INVALID == rxs[rx_sw_if_index])
142 13 : continue;
143 :
144 3 : rx = ip_punt_redirect_get (rxs[rx_sw_if_index]);
145 :
146 3 : s = format (s, " rx %U via:\n",
147 : format_vnet_sw_interface_name, vnm,
148 : vnet_get_sw_interface (vnm, rx_sw_if_index));
149 3 : s = format (s, " %U", format_fib_path_list, rx->pl, 2);
150 3 : s = format (s, " forwarding\n", format_dpo_id, &rx->dpo, 0);
151 3 : s = format (s, " %U\n", format_dpo_id, &rx->dpo, 0);
152 : }
153 :
154 2 : return (s);
155 : }
156 :
157 : void
158 6 : ip_punt_redirect_walk (fib_protocol_t fproto,
159 : ip_punt_redirect_walk_cb_t cb, void *ctx)
160 : {
161 : ip_punt_redirect_rx_t *rx;
162 : u32 ii, rx_sw_if_index;
163 : index_t *rxs;
164 :
165 6 : rxs = ip_punt_redirect_cfg.redirect_by_rx_sw_if_index[fproto];
166 :
167 24 : vec_foreach_index (ii, rxs)
168 : {
169 18 : if (INDEX_INVALID == rxs[ii])
170 9 : continue;
171 :
172 9 : rx = ip_punt_redirect_get (rxs[ii]);
173 :
174 9 : rx_sw_if_index = (ii == 0 ? ~0 : ii);
175 9 : cb (rx_sw_if_index, rx, ctx);
176 : }
177 6 : }
178 :
179 : static fib_node_t *
180 57 : ip_punt_redirect_get_node (fib_node_index_t index)
181 : {
182 57 : ip_punt_redirect_rx_t *ipr = ip_punt_redirect_get (index);
183 57 : return (&(ipr->node));
184 : }
185 :
186 : static ip_punt_redirect_rx_t *
187 57 : ip_punt_redirect_get_from_node (fib_node_t * node)
188 : {
189 57 : return ((ip_punt_redirect_rx_t *) (((char *) node) -
190 : STRUCT_OFFSET_OF (ip_punt_redirect_rx_t,
191 : node)));
192 : }
193 :
194 : static void
195 0 : ip_punt_redirect_last_lock_gone (fib_node_t * node)
196 : {
197 : /*
198 : * the lifetime of the entry is managed by the table.
199 : */
200 0 : ASSERT (0);
201 0 : }
202 :
203 : /*
204 : * A back walk has reached this BIER entry
205 : */
206 : static fib_node_back_walk_rc_t
207 57 : ip_punt_redirect_back_walk_notify (fib_node_t * node,
208 : fib_node_back_walk_ctx_t * ctx)
209 : {
210 : /*
211 : * re-populate the ECMP tables with new choices
212 : */
213 57 : ip_punt_redirect_rx_t *ipr = ip_punt_redirect_get_from_node (node);
214 :
215 57 : ip_punt_redirect_stack (ipr);
216 :
217 : /*
218 : * no need to propagate further up the graph, since there's nothing there
219 : */
220 57 : return (FIB_NODE_BACK_WALK_CONTINUE);
221 : }
222 :
223 : /*
224 : * The BIER fmask's graph node virtual function table
225 : */
226 : static const fib_node_vft_t ip_punt_redirect_vft = {
227 : .fnv_get = ip_punt_redirect_get_node,
228 : .fnv_last_lock = ip_punt_redirect_last_lock_gone,
229 : .fnv_back_walk = ip_punt_redirect_back_walk_notify,
230 : };
231 :
232 : static clib_error_t *
233 575 : ip_punt_drop_init (vlib_main_t * vm)
234 : {
235 575 : fib_node_register_type (FIB_NODE_TYPE_IP_PUNT_REDIRECT,
236 : &ip_punt_redirect_vft);
237 :
238 575 : ip4_punt_policer_cfg.fq_index =
239 575 : vlib_frame_queue_main_init (ip4_punt_policer_node.index, 0);
240 575 : ip6_punt_policer_cfg.fq_index =
241 575 : vlib_frame_queue_main_init (ip6_punt_policer_node.index, 0);
242 :
243 575 : return (NULL);
244 : }
245 :
246 46655 : VLIB_INIT_FUNCTION (ip_punt_drop_init);
247 :
248 : /*
249 : * fd.io coding-style-patch-verification: ON
250 : *
251 : * Local Variables:
252 : * eval: (c-set-style "gnu")
253 : * End:
254 : */
|