Line data Source code
1 : /*
2 : * Copyright (c) 2020 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 : * @file nat44_ei.h
17 : * NAT44 endpoint independent plugin declarations
18 : */
19 : #ifndef __included_nat44_ei_h__
20 : #define __included_nat44_ei_h__
21 :
22 : #include <vlib/log.h>
23 : #include <vlibapi/api.h>
24 :
25 : #include <vnet/vnet.h>
26 : #include <vnet/ip/ip.h>
27 : #include <vnet/ethernet/ethernet.h>
28 : #include <vnet/ip/icmp46_packet.h>
29 : #include <vnet/api_errno.h>
30 : #include <vnet/fib/fib_source.h>
31 :
32 : #include <vppinfra/dlist.h>
33 : #include <vppinfra/error.h>
34 : #include <vppinfra/bihash_8_8.h>
35 : #include <vppinfra/hash.h>
36 :
37 : #include <nat/lib/lib.h>
38 : #include <nat/lib/inlines.h>
39 : #include <nat/lib/nat_proto.h>
40 :
41 : /* default number of worker handoff frame queue elements */
42 : #define NAT_FQ_NELTS_DEFAULT 64
43 :
44 : /* External address and port allocation modes */
45 : #define foreach_nat44_ei_addr_and_port_alloc_alg \
46 : _ (0, DEFAULT, "default") \
47 : _ (1, MAPE, "map-e") \
48 : _ (2, RANGE, "port-range")
49 :
50 : typedef enum
51 : {
52 : #define _(v, N, s) NAT44_EI_ADDR_AND_PORT_ALLOC_ALG_##N = v,
53 : foreach_nat44_ei_addr_and_port_alloc_alg
54 : #undef _
55 : } nat44_ei_addr_and_port_alloc_alg_t;
56 :
57 : /* Interface flags */
58 : #define NAT44_EI_INTERFACE_FLAG_IS_INSIDE (1 << 0)
59 : #define NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE (1 << 1)
60 :
61 : /* Session flags */
62 : #define NAT44_EI_SESSION_FLAG_STATIC_MAPPING (1 << 0)
63 : #define NAT44_EI_SESSION_FLAG_UNKNOWN_PROTO (1 << 1)
64 :
65 : /* Static mapping flags */
66 : #define NAT44_EI_SM_FLAG_ADDR_ONLY (1 << 0)
67 : #define NAT44_EI_SM_FLAG_IDENTITY_NAT (1 << 1)
68 : #define NAT44_EI_SM_FLAG_SWITCH_ADDRESS (1 << 2)
69 :
70 : typedef struct
71 : {
72 : ip4_address_t addr;
73 : u32 fib_index;
74 : u32 busy_ports[NAT_N_PROTOCOLS];
75 : u32 *busy_ports_per_thread[NAT_N_PROTOCOLS];
76 : uword *busy_port_bitmap[NAT_N_PROTOCOLS];
77 : } nat44_ei_address_t;
78 :
79 : clib_error_t *nat44_ei_api_hookup (vlib_main_t *vm);
80 :
81 : /* NAT address and port allocation function */
82 : typedef int (nat44_ei_alloc_out_addr_and_port_function_t) (
83 : nat44_ei_address_t *addresses, u32 fib_index, u32 thread_index,
84 : nat_protocol_t proto, ip4_address_t s_addr, ip4_address_t *addr, u16 *port,
85 : u16 port_per_thread, u32 snat_thread_index);
86 :
87 : typedef struct
88 : {
89 : u16 identifier;
90 : u16 sequence;
91 : } icmp_echo_header_t;
92 :
93 : typedef struct
94 : {
95 : u16 src_port, dst_port;
96 : } tcp_udp_header_t;
97 :
98 : typedef struct
99 : {
100 : union
101 : {
102 : struct
103 : {
104 : ip4_address_t addr;
105 : u32 fib_index;
106 : };
107 : u64 as_u64;
108 : };
109 : } nat44_ei_user_key_t;
110 :
111 : typedef struct
112 : {
113 : /* maximum number of users */
114 : u32 users;
115 : /* maximum number of sessions */
116 : u32 sessions;
117 : /* maximum number of ssessions per user */
118 : u32 user_sessions;
119 :
120 : /* plugin features */
121 : u8 static_mapping_only;
122 : u8 connection_tracking;
123 : u8 out2in_dpo;
124 :
125 : u32 inside_vrf;
126 : u32 outside_vrf;
127 :
128 : } nat44_ei_config_t;
129 :
130 : typedef struct
131 : {
132 : ip4_address_t l_addr;
133 : ip4_address_t pool_addr;
134 : u16 l_port;
135 : u16 e_port;
136 : u32 sw_if_index;
137 : u32 vrf_id;
138 : u32 flags;
139 : nat_protocol_t proto;
140 : u8 *tag;
141 : } nat44_ei_static_map_resolve_t;
142 :
143 : typedef struct
144 : {
145 : /* backend IP address */
146 : ip4_address_t addr;
147 : /* backend port number */
148 : u16 port;
149 : /* probability of the backend to be randomly matched */
150 : u8 probability;
151 : u8 prefix;
152 : /* backend FIB table */
153 : u32 vrf_id;
154 : u32 fib_index;
155 : } nat44_ei_lb_addr_port_t;
156 :
157 : typedef struct
158 : {
159 : /* preferred pool address */
160 : ip4_address_t pool_addr;
161 : /* local IP address */
162 : ip4_address_t local_addr;
163 : /* external IP address */
164 : ip4_address_t external_addr;
165 : /* local port */
166 : u16 local_port;
167 : /* external port */
168 : u16 external_port;
169 : /* local FIB table */
170 : u32 vrf_id;
171 : u32 fib_index;
172 : /* protocol */
173 : nat_protocol_t proto;
174 : /* worker threads used by backends/local host */
175 : u32 *workers;
176 : /* opaque string tag */
177 : u8 *tag;
178 : /* backends for load-balancing mode */
179 : nat44_ei_lb_addr_port_t *locals;
180 : /* flags */
181 : u32 flags;
182 : } nat44_ei_static_mapping_t;
183 :
184 : typedef struct
185 : {
186 : u32 sw_if_index;
187 : u8 flags;
188 : } nat44_ei_interface_t;
189 :
190 : typedef struct
191 : {
192 : u32 fib_index;
193 : u32 ref_count;
194 : } nat44_ei_fib_t;
195 :
196 : typedef struct
197 : {
198 : u32 fib_index;
199 : u32 refcount;
200 : } nat44_ei_outside_fib_t;
201 :
202 : typedef CLIB_PACKED (struct {
203 : /* Outside network tuple */
204 : struct
205 : {
206 : ip4_address_t addr;
207 : u32 fib_index;
208 : u16 port;
209 : } out2in;
210 :
211 : /* Inside network tuple */
212 : struct
213 : {
214 : ip4_address_t addr;
215 : u32 fib_index;
216 : u16 port;
217 : } in2out;
218 :
219 : nat_protocol_t nat_proto;
220 :
221 : /* Flags */
222 : u32 flags;
223 :
224 : /* Per-user translations */
225 : u32 per_user_index;
226 : u32 per_user_list_head_index;
227 :
228 : /* head of LRU list in which this session is tracked */
229 : u32 lru_head_index;
230 : /* index in global LRU list */
231 : u32 lru_index;
232 : f64 last_lru_update;
233 :
234 : /* Last heard timer */
235 : f64 last_heard;
236 :
237 : /* Last HA refresh */
238 : f64 ha_last_refreshed;
239 :
240 : /* Counters */
241 : u64 total_bytes;
242 : u32 total_pkts;
243 :
244 : /* External host address and port */
245 : ip4_address_t ext_host_addr;
246 : u16 ext_host_port;
247 :
248 : /* External host address and port after translation */
249 : ip4_address_t ext_host_nat_addr;
250 : u16 ext_host_nat_port;
251 :
252 : /* TCP session state */
253 : u8 state;
254 : u32 i2o_fin_seq;
255 : u32 o2i_fin_seq;
256 : u64 tcp_closed_timestamp;
257 :
258 : /* user index */
259 : u32 user_index;
260 : }) nat44_ei_session_t;
261 :
262 : typedef CLIB_PACKED (struct {
263 : ip4_address_t addr;
264 : u32 fib_index;
265 : u32 sessions_per_user_list_head_index;
266 : u32 nsessions;
267 : u32 nstaticsessions;
268 : }) nat44_ei_user_t;
269 :
270 : typedef struct
271 : {
272 : /* Find-a-user => src address lookup */
273 : clib_bihash_8_8_t user_hash;
274 :
275 : /* User pool */
276 : nat44_ei_user_t *users;
277 :
278 : /* Session pool */
279 : nat44_ei_session_t *sessions;
280 :
281 : /* Pool of doubly-linked list elements */
282 : dlist_elt_t *list_pool;
283 :
284 : /* LRU session list - head is stale, tail is fresh */
285 : dlist_elt_t *lru_pool;
286 : u32 tcp_trans_lru_head_index;
287 : u32 tcp_estab_lru_head_index;
288 : u32 udp_lru_head_index;
289 : u32 icmp_lru_head_index;
290 : u32 unk_proto_lru_head_index;
291 :
292 : /* NAT thread index */
293 : u32 snat_thread_index;
294 :
295 : /* real thread index */
296 : u32 thread_index;
297 :
298 : } nat44_ei_main_per_thread_data_t;
299 :
300 : typedef struct
301 : {
302 : u32 cached_sw_if_index;
303 : uword *cached_presence_by_ip4_address;
304 : } nat44_ei_runtime_t;
305 :
306 : typedef struct
307 : {
308 : u32 thread_index;
309 : f64 now;
310 : } nat44_ei_is_idle_session_ctx_t;
311 :
312 : typedef struct nat44_ei_main_s
313 : {
314 : u32 translations;
315 : u32 translation_buckets;
316 : u32 user_buckets;
317 :
318 : u8 out2in_dpo;
319 : u8 forwarding_enabled;
320 : u8 static_mapping_only;
321 : u8 static_mapping_connection_tracking;
322 :
323 : u16 mss_clamping;
324 :
325 : /* Find a static mapping by local */
326 : clib_bihash_8_8_t static_mapping_by_local;
327 :
328 : /* Find a static mapping by external */
329 : clib_bihash_8_8_t static_mapping_by_external;
330 :
331 : /* Static mapping pool */
332 : nat44_ei_static_mapping_t *static_mappings;
333 :
334 : /* Interface pool */
335 : nat44_ei_interface_t *interfaces;
336 : nat44_ei_interface_t *output_feature_interfaces;
337 : // broken api backward compatibility
338 : nat44_ei_interface_t *output_feature_dummy_interfaces;
339 :
340 : /* Is translation memory size calculated or user defined */
341 : u8 translation_memory_size_set;
342 :
343 : u32 max_users_per_thread;
344 : u32 max_translations_per_thread;
345 : u32 max_translations_per_user;
346 :
347 : u32 inside_vrf_id;
348 : u32 inside_fib_index;
349 :
350 : u32 outside_vrf_id;
351 : u32 outside_fib_index;
352 :
353 : /* Thread settings */
354 : u32 num_workers;
355 : u32 first_worker_index;
356 : u32 *workers;
357 : u16 port_per_thread;
358 :
359 : /* Main lookup tables */
360 : clib_bihash_8_8_t out2in;
361 : clib_bihash_8_8_t in2out;
362 :
363 : /* Per thread data */
364 : nat44_ei_main_per_thread_data_t *per_thread_data;
365 :
366 : /* Vector of outside addresses */
367 : nat44_ei_address_t *addresses;
368 :
369 : nat44_ei_alloc_out_addr_and_port_function_t *alloc_addr_and_port;
370 : /* Address and port allocation type */
371 : nat44_ei_addr_and_port_alloc_alg_t addr_and_port_alloc_alg;
372 : /* Port set parameters (MAP-E) */
373 : u8 psid_offset;
374 : u8 psid_length;
375 : u16 psid;
376 : /* Port range parameters */
377 : u16 start_port;
378 : u16 end_port;
379 :
380 : /* vector of fibs */
381 : nat44_ei_fib_t *fibs;
382 :
383 : /* vector of outside fibs */
384 : nat44_ei_outside_fib_t *outside_fibs;
385 :
386 : /* sw_if_indices whose intfc addresses should be auto-added */
387 : u32 *auto_add_sw_if_indices;
388 :
389 : /* vector of interface address static mappings to resolve. */
390 : nat44_ei_static_map_resolve_t *to_resolve;
391 :
392 : u32 in2out_node_index;
393 : u32 out2in_node_index;
394 : u32 in2out_output_node_index;
395 :
396 : u32 fq_in2out_index;
397 : u32 fq_in2out_output_index;
398 : u32 fq_out2in_index;
399 :
400 : /* Randomize port allocation order */
401 : u32 random_seed;
402 :
403 : nat_timeouts_t timeouts;
404 :
405 : /* counters */
406 : vlib_simple_counter_main_t total_users;
407 : vlib_simple_counter_main_t total_sessions;
408 : vlib_simple_counter_main_t user_limit_reached;
409 :
410 : #define _(x) vlib_simple_counter_main_t x;
411 : struct
412 : {
413 : struct
414 : {
415 : struct
416 : {
417 : foreach_nat_counter;
418 : } in2out;
419 :
420 : struct
421 : {
422 : foreach_nat_counter;
423 : } out2in;
424 :
425 : } fastpath;
426 :
427 : struct
428 : {
429 : struct
430 : {
431 : foreach_nat_counter;
432 : } in2out;
433 :
434 : struct
435 : {
436 : foreach_nat_counter;
437 : } out2in;
438 : } slowpath;
439 :
440 : vlib_simple_counter_main_t hairpinning;
441 : } counters;
442 : #undef _
443 :
444 : /* API message ID base */
445 : u16 msg_id_base;
446 :
447 : /* log class */
448 : vlib_log_class_t log_class;
449 : /* logging level */
450 : u8 log_level;
451 :
452 : /* convenience */
453 : api_main_t *api_main;
454 : ip4_main_t *ip4_main;
455 : ip_lookup_main_t *ip4_lookup_main;
456 :
457 : fib_source_t fib_src_hi;
458 : fib_source_t fib_src_low;
459 :
460 : /* pat (port address translation)
461 : * dynamic mapping enabled or conneciton tracking */
462 : u8 pat;
463 :
464 : /* number of worker handoff frame queue elements */
465 : u32 frame_queue_nelts;
466 :
467 : /* nat44 plugin enabled */
468 : u8 enabled;
469 :
470 : /* hairpinning registration counter */
471 : u32 hairpin_reg;
472 :
473 : nat44_ei_config_t rconfig;
474 :
475 : u32 in2out_hairpinning_finish_ip4_lookup_node_fq_index;
476 : u32 in2out_hairpinning_finish_interface_output_node_fq_index;
477 : u32 hairpinning_fq_index;
478 :
479 : vnet_main_t *vnet_main;
480 : } nat44_ei_main_t;
481 :
482 : extern nat44_ei_main_t nat44_ei_main;
483 :
484 : int nat44_ei_plugin_enable (nat44_ei_config_t c);
485 : int nat44_ei_plugin_disable ();
486 :
487 : int nat44_ei_add_interface (u32 sw_if_index, u8 is_inside);
488 : int nat44_ei_del_interface (u32 sw_if_index, u8 is_inside);
489 : int nat44_ei_add_output_interface (u32 sw_if_index);
490 : int nat44_ei_del_output_interface (u32 sw_if_index);
491 : int nat44_ei_add_address (ip4_address_t *addr, u32 vrf_id);
492 : int nat44_ei_del_address (ip4_address_t addr, u8 delete_sm);
493 : int nat44_ei_add_interface_address (u32 sw_if_index);
494 : int nat44_ei_del_interface_address (u32 sw_if_index);
495 :
496 : /**
497 : * @brief Delete specific NAT44 EI user and his sessions
498 : *
499 : * @param addr IPv4 address
500 : * @param fib_index FIB table index
501 : */
502 : int nat44_ei_user_del (ip4_address_t *addr, u32 fib_index);
503 :
504 : /**
505 : * @brief Delete session for static mapping
506 : *
507 : * @param addr IPv4 address
508 : * @param fib_index FIB table index
509 : */
510 : void nat44_ei_static_mapping_del_sessions (
511 : nat44_ei_main_t *nm, nat44_ei_main_per_thread_data_t *tnm,
512 : nat44_ei_user_key_t u_key, int addr_only, ip4_address_t e_addr, u16 e_port);
513 :
514 : u32 nat44_ei_get_in2out_worker_index (ip4_header_t *ip0, u32 rx_fib_index0,
515 : u8 is_output);
516 :
517 : u32 nat44_ei_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip0,
518 : u32 rx_fib_index0, u8 is_output);
519 :
520 : /**
521 : * @brief Set address and port assignment algorithm to default/standard
522 : */
523 : void nat44_ei_set_alloc_default (void);
524 :
525 : /**
526 : * @brief Set address and port assignment algorithm for MAP-E CE
527 : *
528 : * @param psid Port Set Identifier value
529 : * @param psid_offset number of offset bits
530 : * @param psid_length length of PSID
531 : */
532 : void nat44_ei_set_alloc_mape (u16 psid, u16 psid_offset, u16 psid_length);
533 :
534 : /**
535 : * @brief Set address and port assignment algorithm for port range
536 : *
537 : * @param start_port beginning of the port range
538 : * @param end_port end of the port range
539 : */
540 : void nat44_ei_set_alloc_range (u16 start_port, u16 end_port);
541 :
542 : int nat44_ei_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
543 : u16 l_port, u16 e_port, nat_protocol_t proto,
544 : u32 vrf_id, u32 sw_if_index, u32 flags,
545 : ip4_address_t pool_addr, u8 *tag);
546 :
547 : int nat44_ei_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
548 : u16 l_port, u16 e_port, nat_protocol_t proto,
549 : u32 vrf_id, u32 sw_if_index, u32 flags);
550 :
551 : /**
552 : * @brief Delete NAT44-EI session
553 : *
554 : * @param addr IPv4 address
555 : * @param port L4 port number
556 : * @param proto L4 protocol
557 : * @param vrf_id VRF ID
558 : * @param is_in 1 = inside network address and port pair, 0 = outside
559 : *
560 : * @return 0 on success, non-zero value otherwise
561 : */
562 : int nat44_ei_del_session (nat44_ei_main_t *nm, ip4_address_t *addr, u16 port,
563 : nat_protocol_t proto, u32 vrf_id, int is_in);
564 :
565 : /**
566 : * @brief Match NAT44-EI static mapping.
567 : *
568 : * @param key address and port to match
569 : * @param addr external/local address of the matched mapping
570 : * @param port port of the matched mapping
571 : * @param fib_index fib index of the matched mapping
572 : * @param by_external if 0 match by local address otherwise match by
573 : * external address
574 : * @param is_addr_only 1 if matched mapping is address only
575 : * @param is_identity_nat 1 if indentity mapping
576 : *
577 : * @returns 0 if match found otherwise 1.
578 : */
579 : int nat44_ei_static_mapping_match (ip4_address_t match_addr, u16 match_port,
580 : u32 match_fib_index,
581 : nat_protocol_t match_protocol,
582 : ip4_address_t *mapping_addr,
583 : u16 *mapping_port, u32 *mapping_fib_index,
584 : u8 by_external, u8 *is_addr_only,
585 : u8 *is_identity_nat);
586 :
587 : /**
588 : * @brief Clear all active NAT44-EI sessions.
589 : */
590 : void nat44_ei_sessions_clear ();
591 :
592 : nat44_ei_user_t *nat44_ei_user_get_or_create (nat44_ei_main_t *nm,
593 : ip4_address_t *addr,
594 : u32 fib_index, u32 thread_index);
595 :
596 : nat44_ei_session_t *nat44_ei_session_alloc_or_recycle (nat44_ei_main_t *nm,
597 : nat44_ei_user_t *u,
598 : u32 thread_index,
599 : f64 now);
600 :
601 : void nat44_ei_free_session_data_v2 (nat44_ei_main_t *nm, nat44_ei_session_t *s,
602 : u32 thread_index, u8 is_ha);
603 :
604 : void nat44_ei_free_outside_address_and_port (nat44_ei_address_t *addresses,
605 : u32 thread_index,
606 : ip4_address_t *addr, u16 port,
607 : nat_protocol_t protocol);
608 :
609 : int nat44_ei_set_outside_address_and_port (nat44_ei_address_t *addresses,
610 : u32 thread_index,
611 : ip4_address_t addr, u16 port,
612 : nat_protocol_t protocol);
613 :
614 : void nat44_ei_free_session_data (nat44_ei_main_t *nm, nat44_ei_session_t *s,
615 : u32 thread_index, u8 is_ha);
616 :
617 : int nat44_ei_set_workers (uword *bitmap);
618 :
619 : void nat44_ei_add_del_address_dpo (ip4_address_t addr, u8 is_add);
620 :
621 : void nat44_ei_delete_session (nat44_ei_main_t *nm, nat44_ei_session_t *ses,
622 : u32 thread_index);
623 :
624 : /* Call back functions for clib_bihash_add_or_overwrite_stale */
625 : int nat44_i2o_is_idle_session_cb (clib_bihash_kv_8_8_t *kv, void *arg);
626 : int nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t *kv, void *arg);
627 :
628 : int nat44_ei_set_frame_queue_nelts (u32 frame_queue_nelts);
629 :
630 : always_inline bool
631 31501 : nat44_ei_is_session_static (nat44_ei_session_t *s)
632 : {
633 31501 : return (s->flags & NAT44_EI_SESSION_FLAG_STATIC_MAPPING);
634 : }
635 :
636 : always_inline bool
637 10536 : nat44_ei_is_unk_proto_session (nat44_ei_session_t *s)
638 : {
639 10536 : return (s->flags & NAT44_EI_SESSION_FLAG_UNKNOWN_PROTO);
640 : }
641 :
642 : always_inline bool
643 418 : nat44_ei_interface_is_inside (nat44_ei_interface_t *i)
644 : {
645 418 : return (i->flags & NAT44_EI_INTERFACE_FLAG_IS_INSIDE);
646 : }
647 :
648 : always_inline bool
649 21700 : nat44_ei_interface_is_outside (nat44_ei_interface_t *i)
650 : {
651 21700 : return (i->flags & NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE);
652 : }
653 :
654 : always_inline bool
655 487 : is_sm_addr_only (u32 f)
656 : {
657 487 : return (f & NAT44_EI_SM_FLAG_ADDR_ONLY);
658 : }
659 :
660 : always_inline bool
661 307 : is_sm_identity_nat (u32 f)
662 : {
663 307 : return (f & NAT44_EI_SM_FLAG_IDENTITY_NAT);
664 : }
665 :
666 : always_inline bool
667 41 : is_sm_switch_address (u32 f)
668 : {
669 41 : return (f & NAT44_EI_SM_FLAG_SWITCH_ADDRESS);
670 : }
671 :
672 : /* logging */
673 : #define nat44_ei_log_err(...) \
674 : vlib_log (VLIB_LOG_LEVEL_ERR, nat44_ei_main.log_class, __VA_ARGS__)
675 : #define nat44_ei_log_warn(...) \
676 : vlib_log (VLIB_LOG_LEVEL_WARNING, nat44_ei_main.log_class, __VA_ARGS__)
677 : #define nat44_ei_log_notice(...) \
678 : vlib_log (VLIB_LOG_LEVEL_NOTICE, nat44_ei_main.log_class, __VA_ARGS__)
679 : #define nat44_ei_log_info(...) \
680 : vlib_log (VLIB_LOG_LEVEL_INFO, nat44_ei_main.log_class, __VA_ARGS__)
681 : #define nat44_ei_log_debug(...) \
682 : vlib_log (VLIB_LOG_LEVEL_DEBUG, nat44_ei_main.log_class, __VA_ARGS__)
683 :
684 : #endif /* __included_nat44_ei_h__ */
685 : /*
686 : * fd.io coding-style-patch-verification: ON
687 : *
688 : * Local Variables:
689 : * eval: (c-set-style "gnu")
690 : * End:
691 : */
|