LCOV - code coverage report
Current view: top level - vnet/ip - punt.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 243 393 61.8 %
Date: 2023-07-05 22:20:52 Functions: 36 41 87.8 %

          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             : /**
      17             :  * @file
      18             :  * @brief Local TCP/IP stack punt infrastructure.
      19             :  *
      20             :  * Provides a set of VPP nodes together with the relevant APIs and CLI
      21             :  * commands in order to adjust and dispatch packets from the VPP data plane
      22             :  * to the local TCP/IP stack
      23             :  */
      24             : 
      25             : #include <vnet/ip/ip.h>
      26             : #include <vlib/vlib.h>
      27             : #include <vnet/udp/udp.h>
      28             : #include <vnet/tcp/tcp.h>
      29             : #include <vnet/ip/punt.h>
      30             : #include <vlib/unix/unix.h>
      31             : 
      32             : #include <stdio.h>
      33             : #include <unistd.h>
      34             : #include <sys/socket.h>
      35             : #include <sys/uio.h>
      36             : #include <stdlib.h>
      37             : 
      38             : punt_main_t punt_main;
      39             : 
      40             : char *
      41          70 : vnet_punt_get_server_pathname (void)
      42             : {
      43          70 :   punt_main_t *pm = &punt_main;
      44          70 :   return pm->sun_path;
      45             : }
      46             : 
      47             : static void
      48          26 : punt_client_l4_db_add (ip_address_family_t af, u16 port, u32 index)
      49             : {
      50          26 :   punt_main_t *pm = &punt_main;
      51             : 
      52          26 :   pm->db.clients_by_l4_port = hash_set (pm->db.clients_by_l4_port,
      53             :                                         punt_client_l4_mk_key (af, port),
      54             :                                         index);
      55          26 : }
      56             : 
      57             : static u32
      58          27 : punt_client_l4_db_remove (ip_address_family_t af, u16 port)
      59             : {
      60          27 :   punt_main_t *pm = &punt_main;
      61          27 :   u32 key, index = ~0;
      62             :   uword *p;
      63             : 
      64          27 :   key = punt_client_l4_mk_key (af, port);
      65          27 :   p = hash_get (pm->db.clients_by_l4_port, key);
      66             : 
      67          27 :   if (p)
      68          26 :     index = p[0];
      69             : 
      70          27 :   hash_unset (pm->db.clients_by_l4_port, key);
      71             : 
      72          27 :   return (index);
      73             : }
      74             : 
      75             : static void
      76           4 : punt_client_ip_proto_db_add (ip_address_family_t af,
      77             :                              ip_protocol_t proto, u32 index)
      78             : {
      79           4 :   punt_main_t *pm = &punt_main;
      80             : 
      81           4 :   pm->db.clients_by_ip_proto = hash_set (pm->db.clients_by_ip_proto,
      82             :                                          punt_client_ip_proto_mk_key (af,
      83             :                                                                       proto),
      84             :                                          index);
      85           4 : }
      86             : 
      87             : static u32
      88           4 : punt_client_ip_proto_db_remove (ip_address_family_t af, ip_protocol_t proto)
      89             : {
      90           4 :   punt_main_t *pm = &punt_main;
      91           4 :   u32 key, index = ~0;
      92             :   uword *p;
      93             : 
      94           4 :   key = punt_client_ip_proto_mk_key (af, proto);
      95           4 :   p = hash_get (pm->db.clients_by_ip_proto, key);
      96             : 
      97           4 :   if (p)
      98           4 :     index = p[0];
      99             : 
     100           4 :   hash_unset (pm->db.clients_by_ip_proto, key);
     101             : 
     102           4 :   return (index);
     103             : }
     104             : 
     105             : static void
     106           5 : punt_client_exception_db_add (vlib_punt_reason_t reason, u32 pci)
     107             : {
     108           5 :   punt_main_t *pm = &punt_main;
     109             : 
     110           9 :   vec_validate_init_empty (pm->db.clients_by_exception, reason, ~0);
     111             : 
     112           5 :   pm->db.clients_by_exception[reason] = pci;
     113           5 : }
     114             : 
     115             : static u32
     116           5 : punt_client_exception_db_remove (vlib_punt_reason_t reason)
     117             : {
     118           5 :   punt_main_t *pm = &punt_main;
     119           5 :   u32 pci = ~0;
     120             : 
     121           5 :   if (punt_client_exception_get (reason))
     122             :     {
     123           5 :       pci = pm->db.clients_by_exception[reason];
     124           5 :       pm->db.clients_by_exception[reason] = ~0;
     125             :     }
     126             : 
     127           5 :   return pci;
     128             : }
     129             : 
     130             : static clib_error_t *
     131           0 : punt_socket_read_ready (clib_file_t * uf)
     132             : {
     133           0 :   vlib_main_t *vm = vlib_get_main ();
     134           0 :   punt_main_t *pm = &punt_main;
     135             : 
     136             :   /** Schedule the rx node */
     137           0 :   vlib_node_set_interrupt_pending (vm, punt_socket_rx_node.index);
     138           0 :   vec_add1 (pm->ready_fds, uf->file_descriptor);
     139             : 
     140           0 :   return 0;
     141             : }
     142             : 
     143             : static clib_error_t *
     144          26 : punt_socket_register_l4 (vlib_main_t * vm,
     145             :                          ip_address_family_t af,
     146             :                          u8 protocol, u16 port, char *client_pathname)
     147             : {
     148          26 :   punt_main_t *pm = &punt_main;
     149             :   punt_client_t *c;
     150             : 
     151             :   /* For now we only support UDP punt */
     152          26 :   if (protocol != IP_PROTOCOL_UDP)
     153           0 :     return clib_error_return (0,
     154             :                               "only UDP protocol (%d) is supported, got %d",
     155             :                               IP_PROTOCOL_UDP, protocol);
     156             : 
     157          26 :   if (port == (u16) ~ 0)
     158           0 :     return clib_error_return (0, "UDP port number required");
     159             : 
     160          26 :   c = punt_client_l4_get (af, port);
     161             : 
     162          26 :   if (NULL == c)
     163             :     {
     164          26 :       pool_get_zero (pm->punt_client_pool, c);
     165          26 :       punt_client_l4_db_add (af, port, c - pm->punt_client_pool);
     166             :     }
     167             : 
     168          26 :   snprintf (c->caddr.sun_path, sizeof (c->caddr.sun_path), "%s",
     169             :             client_pathname);
     170          26 :   c->caddr.sun_family = AF_UNIX;
     171          26 :   c->reg.type = PUNT_TYPE_L4;
     172          26 :   c->reg.punt.l4.port = port;
     173          26 :   c->reg.punt.l4.protocol = protocol;
     174          26 :   c->reg.punt.l4.af = af;
     175             : 
     176          26 :   u32 node_index = (af == AF_IP4 ?
     177          26 :                     udp4_punt_socket_node.index :
     178             :                     udp6_punt_socket_node.index);
     179             : 
     180          26 :   udp_register_dst_port (vm, port, node_index, af == AF_IP4);
     181             : 
     182          26 :   return (NULL);
     183             : }
     184             : 
     185             : static clib_error_t *
     186           4 : punt_socket_register_ip_proto (vlib_main_t * vm,
     187             :                                ip_address_family_t af,
     188             :                                ip_protocol_t proto, char *client_pathname)
     189             : {
     190           4 :   punt_main_t *pm = &punt_main;
     191             :   punt_client_t *c;
     192             : 
     193           4 :   c = punt_client_ip_proto_get (af, proto);
     194             : 
     195           4 :   if (NULL == c)
     196             :     {
     197           4 :       pool_get_zero (pm->punt_client_pool, c);
     198           4 :       punt_client_ip_proto_db_add (af, proto, c - pm->punt_client_pool);
     199             :     }
     200             : 
     201           4 :   snprintf (c->caddr.sun_path, sizeof (c->caddr.sun_path), "%s",
     202             :             client_pathname);
     203           4 :   c->caddr.sun_family = AF_UNIX;
     204           4 :   c->reg.type = PUNT_TYPE_IP_PROTO;
     205           4 :   c->reg.punt.ip_proto.protocol = proto;
     206           4 :   c->reg.punt.ip_proto.af = af;
     207             : 
     208           4 :   if (af == AF_IP4)
     209           4 :     ip4_register_protocol (proto, ip4_proto_punt_socket_node.index);
     210             :   else
     211           0 :     ip6_register_protocol (proto, ip6_proto_punt_socket_node.index);
     212             : 
     213           4 :   return (NULL);
     214             : }
     215             : 
     216             : static clib_error_t *
     217           5 : punt_socket_register_exception (vlib_main_t * vm,
     218             :                                 vlib_punt_reason_t reason,
     219             :                                 char *client_pathname)
     220             : {
     221           5 :   punt_main_t *pm = &punt_main;
     222             :   punt_client_t *pc;
     223             : 
     224           5 :   pc = punt_client_exception_get (reason);
     225             : 
     226           5 :   if (NULL == pc)
     227             :     {
     228           5 :       pool_get_zero (pm->punt_client_pool, pc);
     229           5 :       punt_client_exception_db_add (reason, pc - pm->punt_client_pool);
     230             :     }
     231             : 
     232           5 :   snprintf (pc->caddr.sun_path, sizeof (pc->caddr.sun_path), "%s",
     233             :             client_pathname);
     234           5 :   pc->caddr.sun_family = AF_UNIX;
     235           5 :   pc->reg.type = PUNT_TYPE_EXCEPTION;
     236           5 :   pc->reg.punt.exception.reason = reason;
     237             : 
     238           5 :   vlib_punt_register (pm->hdl,
     239           5 :                       pc->reg.punt.exception.reason, "exception-punt-socket");
     240             : 
     241           5 :   return (NULL);
     242             : }
     243             : 
     244             : static clib_error_t *
     245          27 : punt_socket_unregister_l4 (ip_address_family_t af,
     246             :                            ip_protocol_t protocol, u16 port)
     247             : {
     248             :   u32 pci;
     249             : 
     250          27 :   udp_unregister_dst_port (vlib_get_main (), port, af == AF_IP4);
     251             : 
     252          27 :   pci = punt_client_l4_db_remove (af, port);
     253             : 
     254          27 :   if (~0 != pci)
     255          26 :     pool_put_index (punt_main.punt_client_pool, pci);
     256             : 
     257          27 :   return (NULL);
     258             : }
     259             : 
     260             : static clib_error_t *
     261           4 : punt_socket_unregister_ip_proto (ip_address_family_t af, ip_protocol_t proto)
     262             : {
     263             :   u32 pci;
     264             : 
     265           4 :   if (af == AF_IP4)
     266           4 :     ip4_unregister_protocol (proto);
     267             :   else
     268           0 :     ip6_unregister_protocol (proto);
     269             : 
     270           4 :   pci = punt_client_ip_proto_db_remove (af, proto);
     271             : 
     272           4 :   if (~0 != pci)
     273           4 :     pool_put_index (punt_main.punt_client_pool, pci);
     274             : 
     275           4 :   return (NULL);
     276             : }
     277             : 
     278             : static clib_error_t *
     279           5 : punt_socket_unregister_exception (vlib_punt_reason_t reason)
     280             : {
     281             :   u32 pci;
     282             : 
     283           5 :   pci = punt_client_exception_db_remove (reason);
     284             : 
     285           5 :   if (~0 != pci)
     286           5 :     pool_put_index (punt_main.punt_client_pool, pci);
     287             : 
     288           5 :   return (NULL);
     289             : }
     290             : 
     291             : clib_error_t *
     292          35 : vnet_punt_socket_add (vlib_main_t * vm, u32 header_version,
     293             :                       const punt_reg_t * pr, char *client_pathname)
     294             : {
     295          35 :   punt_main_t *pm = &punt_main;
     296             : 
     297          35 :   if (!pm->is_configured)
     298           0 :     return clib_error_return (0, "socket is not configured");
     299             : 
     300          35 :   if (header_version != PUNT_PACKETDESC_VERSION)
     301           0 :     return clib_error_return (0, "Invalid packet descriptor version");
     302             : 
     303          35 :   if (strncmp (client_pathname, vnet_punt_get_server_pathname (),
     304             :                UNIX_PATH_MAX) == 0)
     305           0 :     return clib_error_return (0,
     306             :                               "Punt socket: Invalid client path: %s",
     307             :                               client_pathname);
     308             : 
     309             :   /* Register client */
     310          35 :   switch (pr->type)
     311             :     {
     312          26 :     case PUNT_TYPE_L4:
     313          26 :       return (punt_socket_register_l4 (vm,
     314          26 :                                        pr->punt.l4.af,
     315          26 :                                        pr->punt.l4.protocol,
     316          26 :                                        pr->punt.l4.port, client_pathname));
     317           4 :     case PUNT_TYPE_IP_PROTO:
     318           4 :       return (punt_socket_register_ip_proto (vm,
     319           4 :                                              pr->punt.ip_proto.af,
     320           4 :                                              pr->punt.ip_proto.protocol,
     321             :                                              client_pathname));
     322           5 :     case PUNT_TYPE_EXCEPTION:
     323           5 :       return (punt_socket_register_exception (vm,
     324             :                                               pr->punt.exception.reason,
     325             :                                               client_pathname));
     326             :     }
     327             : 
     328           0 :   return 0;
     329             : }
     330             : 
     331             : clib_error_t *
     332          36 : vnet_punt_socket_del (vlib_main_t * vm, const punt_reg_t * pr)
     333             : {
     334          36 :   punt_main_t *pm = &punt_main;
     335             : 
     336          36 :   if (!pm->is_configured)
     337           0 :     return clib_error_return (0, "socket is not configured");
     338             : 
     339          36 :   switch (pr->type)
     340             :     {
     341          27 :     case PUNT_TYPE_L4:
     342          27 :       return (punt_socket_unregister_l4 (pr->punt.l4.af,
     343          27 :                                          pr->punt.l4.protocol,
     344          27 :                                          pr->punt.l4.port));
     345           4 :     case PUNT_TYPE_IP_PROTO:
     346           4 :       return (punt_socket_unregister_ip_proto (pr->punt.ip_proto.af,
     347           4 :                                                pr->punt.ip_proto.protocol));
     348           5 :     case PUNT_TYPE_EXCEPTION:
     349           5 :       return (punt_socket_unregister_exception (pr->punt.exception.reason));
     350             :     }
     351             : 
     352           0 :   return 0;
     353             : }
     354             : 
     355             : /**
     356             :  * @brief Request IP L4 traffic punt to the local TCP/IP stack.
     357             :  *
     358             :  * @em Note
     359             :  * - UDP is the only protocol supported in the current implementation
     360             :  *
     361             :  * @param vm       vlib_main_t corresponding to the current thread
     362             :  * @param af       IP address family.
     363             :  * @param protocol 8-bits L4 protocol value
     364             :  *                 UDP is 17
     365             :  *                 TCP is 1
     366             :  * @param port     16-bits L4 (TCP/IP) port number when applicable (UDP only)
     367             :  *
     368             :  * @returns 0 on success, non-zero value otherwise
     369             :  */
     370             : static clib_error_t *
     371          14 : punt_l4_add_del (vlib_main_t * vm,
     372             :                  ip_address_family_t af,
     373             :                  ip_protocol_t protocol, u16 port, bool is_add)
     374             : {
     375          14 :   int is_ip4 = af == AF_IP4;
     376             : 
     377             :   /* For now we only support TCP and UDP punt */
     378          14 :   if (protocol != IP_PROTOCOL_UDP && protocol != IP_PROTOCOL_TCP)
     379           0 :     return clib_error_return (0,
     380             :                               "only UDP (%d) and TCP (%d) protocols are supported, got %d",
     381             :                               IP_PROTOCOL_UDP, IP_PROTOCOL_TCP, protocol);
     382             : 
     383          14 :   if (port == (u16) ~ 0)
     384             :     {
     385           0 :       if (protocol == IP_PROTOCOL_UDP)
     386           0 :         udp_punt_unknown (vm, is_ip4, is_add);
     387           0 :       else if (protocol == IP_PROTOCOL_TCP)
     388           0 :         tcp_punt_unknown (vm, is_ip4, is_add);
     389             : 
     390           0 :       return 0;
     391             :     }
     392             : 
     393          14 :   else if (is_add)
     394             :     {
     395          14 :       const vlib_node_registration_t *punt_node =
     396             :         is_ip4 ? &udp4_punt_node : &udp6_punt_node;
     397             : 
     398          14 :       if (protocol == IP_PROTOCOL_TCP)
     399           0 :         return clib_error_return (0, "punt TCP ports is not supported yet");
     400             : 
     401          14 :       udp_register_dst_port (vm, port, punt_node->index, is_ip4);
     402             : 
     403          14 :       return 0;
     404             :     }
     405             :   else
     406             :     {
     407           0 :       if (protocol == IP_PROTOCOL_TCP)
     408           0 :         return clib_error_return (0, "punt TCP ports is not supported yet");
     409             : 
     410           0 :       udp_unregister_dst_port (vm, port, is_ip4);
     411             : 
     412           0 :       return 0;
     413             :     }
     414             : }
     415             : 
     416             : /**
     417             :  * @brief Request exception traffic punt.
     418             :  *
     419             :  * @param reason   Punting reason
     420             :  *
     421             :  * @returns 0 on success, non-zero value otherwise
     422             :  */
     423             : static clib_error_t *
     424           0 : punt_exception_add_del (vlib_punt_reason_t reason, bool is_add)
     425             : {
     426           0 :   punt_main_t *pm = &punt_main;
     427           0 :   int rv = 0;
     428           0 :   vnet_punt_reason_flag_t flag = vlib_punt_reason_get_flags (reason);
     429           0 :   const char *node_name =
     430           0 :     vnet_punt_reason_flag_is_IP6_PACKET (flag) ? "ip6-punt" : "ip4-punt";
     431           0 :   if (is_add)
     432           0 :     rv = vlib_punt_register (pm->hdl, reason, node_name);
     433             :   else
     434           0 :     rv = vlib_punt_unregister (pm->hdl, reason, node_name);
     435           0 :   if (!rv)
     436           0 :     return 0;
     437             :   else
     438           0 :     return clib_error_return (0, is_add ? "Existing punting registration..." :
     439             :                                           "Punting registration not found...");
     440             : }
     441             : 
     442             : clib_error_t *
     443          14 : vnet_punt_add_del (vlib_main_t * vm, const punt_reg_t * pr, bool is_add)
     444             : {
     445          14 :   switch (pr->type)
     446             :     {
     447          14 :     case PUNT_TYPE_L4:
     448          14 :       return (punt_l4_add_del (vm, pr->punt.l4.af, pr->punt.l4.protocol,
     449          14 :                                pr->punt.l4.port, is_add));
     450           0 :     case PUNT_TYPE_EXCEPTION:
     451           0 :       return punt_exception_add_del (pr->punt.exception.reason, is_add);
     452           0 :     case PUNT_TYPE_IP_PROTO:
     453           0 :       break;
     454             :     }
     455             : 
     456           0 :   return (clib_error_return (0, "Unsupported punt type: %d", pr->type));
     457             : }
     458             : 
     459             : static clib_error_t *
     460           0 : punt_cli (vlib_main_t * vm,
     461             :           unformat_input_t * input__, vlib_cli_command_t * cmd)
     462             : {
     463           0 :   unformat_input_t line_input, *input = &line_input;
     464           0 :   clib_error_t *error = NULL;
     465           0 :   bool is_add = true;
     466             :   /* *INDENT-OFF* */
     467           0 :   punt_reg_t pr = {
     468             :     .punt = {
     469             :       .l4 = {
     470             :         .af = AF_IP4,
     471             :         .port = ~0,
     472             :         .protocol = IP_PROTOCOL_UDP,
     473             :       },
     474             :     },
     475             :     .type = PUNT_TYPE_L4,
     476             :   };
     477             :   u32 port;
     478             :   /* *INDENT-ON* */
     479             : 
     480           0 :   if (!unformat_user (input__, unformat_line_input, input))
     481           0 :     return 0;
     482             : 
     483           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     484             :     {
     485           0 :       if (unformat (input, "del"))
     486           0 :         is_add = false;
     487           0 :       else if (unformat (input, "reason %U", unformat_punt_reason,
     488             :                          &pr.punt.exception.reason))
     489           0 :         pr.type = PUNT_TYPE_EXCEPTION;
     490           0 :       else if (unformat (input, "ipv4"))
     491           0 :         pr.punt.l4.af = AF_IP4;
     492           0 :       else if (unformat (input, "ipv6"))
     493           0 :         pr.punt.l4.af = AF_IP6;
     494           0 :       else if (unformat (input, "ip6"))
     495           0 :         pr.punt.l4.af = AF_IP6;
     496           0 :       else if (unformat (input, "%d", &port))
     497           0 :         pr.punt.l4.port = port;
     498           0 :       else if (unformat (input, "all"))
     499           0 :         pr.punt.l4.port = ~0;
     500           0 :       else if (unformat (input, "udp"))
     501           0 :         pr.punt.l4.protocol = IP_PROTOCOL_UDP;
     502           0 :       else if (unformat (input, "tcp"))
     503           0 :         pr.punt.l4.protocol = IP_PROTOCOL_TCP;
     504             :       else
     505             :         {
     506           0 :           error = clib_error_return (0, "parse error: '%U'",
     507             :                                      format_unformat_error, input);
     508           0 :           goto done;
     509             :         }
     510             :     }
     511             : 
     512             :   /* punt both IPv6 and IPv4 when used in CLI */
     513           0 :   error = vnet_punt_add_del (vm, &pr, is_add);
     514           0 :   if (error)
     515             :     {
     516           0 :       clib_error_report (error);
     517             :     }
     518             : 
     519           0 : done:
     520           0 :   unformat_free (input);
     521           0 :   return error;
     522             : }
     523             : 
     524             : /*?
     525             :  * The set of '<em>set punt</em>' commands allows specific IP traffic to
     526             :  * be punted to the host TCP/IP stack
     527             :  *
     528             :  * @em Note
     529             :  * - UDP is the only protocol supported in the current implementation
     530             :  * - All TCP traffic is currently punted to the host by default
     531             :  *
     532             :  * @cliexpar
     533             :  * @parblock
     534             :  * Example of how to request NTP traffic to be punted
     535             :  * @cliexcmd{set punt udp 125}
     536             :  *
     537             :  * Example of how to request all 'unknown' UDP traffic to be punted
     538             :  * @cliexcmd{set punt udp all}
     539             :  *
     540             :  * Example of how to stop all 'unknown' UDP traffic to be punted
     541             :  * @cliexcmd{set punt udp del all}
     542             :  * @endparblock
     543             : ?*/
     544             : /* *INDENT-OFF* */
     545      272887 : VLIB_CLI_COMMAND (punt_command, static) = {
     546             :   .path = "set punt",
     547             :   .short_help = "set punt [IPV4|ip6|ipv6] [UDP|tcp] [del] [ALL|<port-num>]",
     548             :   .function = punt_cli,
     549             : };
     550             : /* *INDENT-ON* */
     551             : 
     552             : static clib_error_t *
     553           0 : punt_socket_register_cmd (vlib_main_t * vm,
     554             :                           unformat_input_t * input__,
     555             :                           vlib_cli_command_t * cmd)
     556             : {
     557           0 :   unformat_input_t line_input, *input = &line_input;
     558           0 :   u8 *socket_name = 0;
     559           0 :   clib_error_t *error = NULL;
     560             :   /* *INDENT-OFF* */
     561           0 :   punt_reg_t pr = {
     562             :     .punt = {
     563             :       .l4 = {
     564             :         .af = AF_IP4,
     565             :         .port = ~0,
     566             :         .protocol = IP_PROTOCOL_UDP,
     567             :       },
     568             :     },
     569             :     .type = PUNT_TYPE_L4,
     570             :   };
     571             :   /* *INDENT-ON* */
     572             : 
     573           0 :   if (!unformat_user (input__, unformat_line_input, input))
     574           0 :     return 0;
     575             : 
     576           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     577             :     {
     578           0 :       if (unformat (input, "ipv4"))
     579           0 :         pr.punt.l4.af = AF_IP4;
     580           0 :       else if (unformat (input, "ipv6"))
     581           0 :         pr.punt.l4.af = AF_IP6;
     582           0 :       else if (unformat (input, "udp"))
     583           0 :         pr.punt.l4.protocol = IP_PROTOCOL_UDP;
     584           0 :       else if (unformat (input, "tcp"))
     585           0 :         pr.punt.l4.protocol = IP_PROTOCOL_TCP;
     586           0 :       else if (unformat (input, "%d", &pr.punt.l4.port))
     587             :         ;
     588           0 :       else if (unformat (input, "all"))
     589           0 :         pr.punt.l4.port = ~0;
     590           0 :       else if (unformat (input, "socket %s", &socket_name))
     591             :         ;
     592           0 :       else if (unformat (input, "reason %U", unformat_punt_reason,
     593             :                          &pr.punt.exception.reason))
     594           0 :         pr.type = PUNT_TYPE_EXCEPTION;
     595             :       else
     596             :         {
     597           0 :           error = clib_error_return (0, "parse error: '%U'",
     598             :                                      format_unformat_error, input);
     599           0 :           goto done;
     600             :         }
     601             :     }
     602             : 
     603           0 :   if (!socket_name)
     604           0 :     error = clib_error_return (0, "socket name not specified");
     605             :   else
     606           0 :     error = vnet_punt_socket_add (vm, 1, &pr, (char *) socket_name);
     607             : 
     608           0 : done:
     609           0 :   unformat_free (input);
     610           0 :   return error;
     611             : }
     612             : 
     613             : /*?
     614             :  *
     615             :  * @cliexpar
     616             :  * @cliexcmd{punt socket register socket punt_l4_foo.sock}
     617             : 
     618             :  ?*/
     619             : /* *INDENT-OFF* */
     620      272887 : VLIB_CLI_COMMAND (punt_socket_register_command, static) =
     621             : {
     622             :   .path = "punt socket register",
     623             :   .function = punt_socket_register_cmd,
     624             :   .short_help = "punt socket register [IPV4|ipv6] [UDP|tcp] [ALL|<port-num>] socket <socket>",
     625             :   .is_mp_safe = 1,
     626             : };
     627             : /* *INDENT-ON* */
     628             : 
     629             : static clib_error_t *
     630           0 : punt_socket_deregister_cmd (vlib_main_t * vm,
     631             :                             unformat_input_t * input__,
     632             :                             vlib_cli_command_t * cmd)
     633             : {
     634           0 :   unformat_input_t line_input, *input = &line_input;
     635           0 :   clib_error_t *error = NULL;
     636             :   /* *INDENT-OFF* */
     637           0 :   punt_reg_t pr = {
     638             :     .punt = {
     639             :       .l4 = {
     640             :         .af = AF_IP4,
     641             :         .port = ~0,
     642             :         .protocol = IP_PROTOCOL_UDP,
     643             :       },
     644             :     },
     645             :     .type = PUNT_TYPE_L4,
     646             :   };
     647             :   /* *INDENT-ON* */
     648             : 
     649           0 :   if (!unformat_user (input__, unformat_line_input, input))
     650           0 :     return 0;
     651             : 
     652           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     653             :     {
     654           0 :       if (unformat (input, "ipv4"))
     655           0 :         pr.punt.l4.af = AF_IP4;
     656           0 :       else if (unformat (input, "ipv6"))
     657           0 :         pr.punt.l4.af = AF_IP6;
     658           0 :       else if (unformat (input, "udp"))
     659           0 :         pr.punt.l4.protocol = IP_PROTOCOL_UDP;
     660           0 :       else if (unformat (input, "tcp"))
     661           0 :         pr.punt.l4.protocol = IP_PROTOCOL_TCP;
     662           0 :       else if (unformat (input, "%d", &pr.punt.l4.port))
     663             :         ;
     664           0 :       else if (unformat (input, "all"))
     665           0 :         pr.punt.l4.port = ~0;
     666           0 :       else if (unformat (input, "reason %U", unformat_punt_reason,
     667             :                          &pr.punt.exception.reason))
     668           0 :         pr.type = PUNT_TYPE_EXCEPTION;
     669             :       else
     670             :         {
     671           0 :           error = clib_error_return (0, "parse error: '%U'",
     672             :                                      format_unformat_error, input);
     673           0 :           goto done;
     674             :         }
     675             :     }
     676             : 
     677           0 :   error = vnet_punt_socket_del (vm, &pr);
     678           0 : done:
     679           0 :   unformat_free (input);
     680           0 :   return error;
     681             : }
     682             : 
     683             : /*?
     684             :  *
     685             :  * @cliexpar
     686             :  * @cliexcmd{punt socket register}
     687             :  ?*/
     688             : /* *INDENT-OFF* */
     689      272887 : VLIB_CLI_COMMAND (punt_socket_deregister_command, static) =
     690             : {
     691             :   .path = "punt socket deregister",
     692             :   .function = punt_socket_deregister_cmd,
     693             :   .short_help = "punt socket deregister [IPV4|ipv6] [UDP|tcp] [ALL|<port-num>]",
     694             :   .is_mp_safe = 1,
     695             : };
     696             : /* *INDENT-ON* */
     697             : 
     698             : void
     699          36 : punt_client_walk (punt_type_t pt, punt_client_walk_cb_t cb, void *ctx)
     700             : {
     701          36 :   punt_main_t *pm = &punt_main;
     702             : 
     703          36 :   switch (pt)
     704             :     {
     705          23 :     case PUNT_TYPE_L4:
     706             :       {
     707             :         u32 pci, key;
     708             : 
     709             :         /* *INDENT-OFF* */
     710        1389 :         hash_foreach(key, pci, pm->db.clients_by_l4_port,
     711             :         ({
     712             :           cb (pool_elt_at_index(pm->punt_client_pool, pci), ctx);
     713             :         }));
     714             :         /* *INDENT-ON* */
     715          23 :         break;
     716             :       }
     717           6 :     case PUNT_TYPE_IP_PROTO:
     718             :       {
     719             :         u32 pci, key;
     720             : 
     721             :         /* *INDENT-OFF* */
     722         333 :         hash_foreach(key, pci, pm->db.clients_by_ip_proto,
     723             :         ({
     724             :           cb (pool_elt_at_index(pm->punt_client_pool, pci), ctx);
     725             :         }));
     726             :         /* *INDENT-ON* */
     727           6 :         break;
     728             :       }
     729           7 :     case PUNT_TYPE_EXCEPTION:
     730             :       {
     731             :         u32 *pci;
     732             : 
     733          25 :         vec_foreach (pci, pm->db.clients_by_exception)
     734             :         {
     735          18 :           if (~0 != *pci)
     736           9 :             cb (pool_elt_at_index (pm->punt_client_pool, *pci), ctx);
     737             :         }
     738             : 
     739           7 :         break;
     740             :       }
     741             :     }
     742          36 : }
     743             : 
     744             : static u8 *
     745           5 : format_punt_client (u8 * s, va_list * args)
     746             : {
     747           5 :   punt_client_t *pc = va_arg (*args, punt_client_t *);
     748             : 
     749           5 :   s = format (s, " punt ");
     750             : 
     751           5 :   switch (pc->reg.type)
     752             :     {
     753           0 :     case PUNT_TYPE_L4:
     754           0 :       s = format (s, "%U %U port %d",
     755           0 :                   format_ip_address_family, pc->reg.punt.l4.af,
     756           0 :                   format_ip_protocol, pc->reg.punt.l4.protocol,
     757           0 :                   pc->reg.punt.l4.port);
     758           0 :       break;
     759           2 :     case PUNT_TYPE_IP_PROTO:
     760           2 :       s = format (s, "%U %U",
     761           2 :                   format_ip_address_family, pc->reg.punt.ip_proto.af,
     762           2 :                   format_ip_protocol, pc->reg.punt.ip_proto.protocol);
     763           2 :       break;
     764           3 :     case PUNT_TYPE_EXCEPTION:
     765           3 :       s = format (s, " %U", format_vlib_punt_reason,
     766           3 :                   pc->reg.punt.exception.reason);
     767           3 :       break;
     768             :     }
     769             : 
     770           5 :   s = format (s, " to socket %s \n", pc->caddr.sun_path);
     771             : 
     772           5 :   return (s);
     773             : }
     774             : 
     775             : static walk_rc_t
     776           5 : punt_client_show_one (const punt_client_t * pc, void *ctx)
     777             : {
     778           5 :   vlib_cli_output (ctx, "%U", format_punt_client, pc);
     779             : 
     780           5 :   return (WALK_CONTINUE);
     781             : }
     782             : 
     783             : static clib_error_t *
     784           4 : punt_socket_show_cmd (vlib_main_t * vm,
     785             :                       unformat_input_t * input__, vlib_cli_command_t * cmd)
     786             : {
     787           4 :   unformat_input_t line_input, *input = &line_input;
     788           4 :   clib_error_t *error = NULL;
     789             :   punt_type_t pt;
     790             : 
     791           4 :   pt = PUNT_TYPE_L4;
     792             : 
     793           4 :   if (!unformat_user (input__, unformat_line_input, input))
     794           1 :     return 0;
     795             : 
     796           6 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     797             :     {
     798           3 :       if (unformat (input, "exception"))
     799           2 :         pt = PUNT_TYPE_EXCEPTION;
     800           1 :       else if (unformat (input, "l4"))
     801           0 :         pt = PUNT_TYPE_L4;
     802           1 :       else if (unformat (input, "ip"))
     803           1 :         pt = PUNT_TYPE_IP_PROTO;
     804             :       else
     805             :         {
     806           0 :           error = clib_error_return (0, "parse error: '%U'",
     807             :                                      format_unformat_error, input);
     808           0 :           goto done;
     809             :         }
     810             :     }
     811             : 
     812           3 :   punt_client_walk (pt, punt_client_show_one, vm);
     813             : 
     814           3 : done:
     815           3 :   unformat_free (input);
     816           3 :   return (error);
     817             : }
     818             : 
     819             : /*?
     820             :  *
     821             :  * @cliexpar
     822             :  * @cliexcmd{show punt socket ipv4}
     823             :  ?*/
     824             : /* *INDENT-OFF* */
     825      272887 : VLIB_CLI_COMMAND (show_punt_socket_registration_command, static) =
     826             : {
     827             :   .path = "show punt socket registrations",
     828             :   .function = punt_socket_show_cmd,
     829             :   .short_help = "show punt socket registrations [l4|exception]",
     830             :   .is_mp_safe = 1,
     831             : };
     832             : /* *INDENT-ON* */
     833             : 
     834             : clib_error_t *
     835         559 : ip_punt_init (vlib_main_t * vm)
     836             : {
     837         559 :   clib_error_t *error = NULL;
     838         559 :   punt_main_t *pm = &punt_main;
     839         559 :   vlib_thread_main_t *tm = vlib_get_thread_main ();
     840             : 
     841         559 :   pm->is_configured = false;
     842         559 :   pm->interface_output_node =
     843         559 :     vlib_get_node_by_name (vm, (u8 *) "interface-output");
     844             : 
     845         559 :   if ((error = vlib_call_init_function (vm, punt_init)))
     846           0 :     return error;
     847             : 
     848         559 :   pm->hdl = vlib_punt_client_register ("ip-punt");
     849             : 
     850         559 :   vec_validate_aligned (pm->thread_data, tm->n_vlib_mains,
     851             :                         CLIB_CACHE_LINE_BYTES);
     852             : 
     853         559 :   return (error);
     854             : }
     855             : 
     856             : u8 *
     857        1721 : format_vnet_punt_reason_flags (u8 *s, va_list *args)
     858             : {
     859        1721 :   vnet_punt_reason_flag_t flag = va_arg (*args, int);
     860             : #define _(pos, len, value, name, str)                                         \
     861             :   if (vnet_punt_reason_flag_is_##name (flag))                                 \
     862             :     s = format (s, "%s ", str);
     863             : 
     864        1721 :   foreach_vnet_punt_reason_flag
     865             : #undef _
     866        1721 :     return (s);
     867             : }
     868             : 
     869       46479 : VLIB_INIT_FUNCTION (ip_punt_init);
     870             : 
     871             : static clib_error_t *
     872         559 : punt_config (vlib_main_t * vm, unformat_input_t * input)
     873             : {
     874         559 :   punt_main_t *pm = &punt_main;
     875         559 :   char *socket_path = 0;
     876             : 
     877         564 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     878             :     {
     879           5 :       if (unformat (input, "socket %s", &socket_path))
     880           5 :         strncpy (pm->sun_path, socket_path, UNIX_PATH_MAX - 1);
     881             :       else
     882           0 :         return clib_error_return (0, "unknown input `%U'",
     883             :                                   format_unformat_error, input);
     884             :     }
     885             : 
     886         559 :   if (socket_path == 0)
     887         554 :     return 0;
     888             : 
     889             :   /* UNIX domain socket */
     890             :   struct sockaddr_un addr;
     891           5 :   if ((pm->socket_fd = socket (AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0)) == -1)
     892             :     {
     893           0 :       return clib_error_return (0, "socket error");
     894             :     }
     895             : 
     896           5 :   clib_memset (&addr, 0, sizeof (addr));
     897           5 :   addr.sun_family = AF_UNIX;
     898           5 :   if (*socket_path == '\0')
     899             :     {
     900           0 :       *addr.sun_path = '\0';
     901           0 :       strncpy (addr.sun_path + 1, socket_path + 1,
     902             :                sizeof (addr.sun_path) - 2);
     903             :     }
     904             :   else
     905             :     {
     906           5 :       strncpy (addr.sun_path, socket_path, sizeof (addr.sun_path) - 1);
     907           5 :       unlink (socket_path);
     908             :     }
     909             : 
     910           5 :   if (bind (pm->socket_fd, (struct sockaddr *) &addr, sizeof (addr)) == -1)
     911             :     {
     912           0 :       return clib_error_return (0, "bind error");
     913             :     }
     914             : 
     915           5 :   int n_bytes = 0x10000;
     916             : 
     917           5 :   if (setsockopt
     918             :       (pm->socket_fd, SOL_SOCKET, SO_SNDBUF, &n_bytes,
     919             :        sizeof (n_bytes)) == -1)
     920             :     {
     921           0 :       return clib_error_return (0, "setsockopt error");
     922             :     }
     923             : 
     924             :   /* Register socket */
     925           5 :   clib_file_main_t *fm = &file_main;
     926           5 :   clib_file_t template = { 0 };
     927           5 :   template.read_function = punt_socket_read_ready;
     928           5 :   template.file_descriptor = pm->socket_fd;
     929           5 :   template.description = format (0, "punt socket %s", socket_path);
     930           5 :   pm->clib_file_index = clib_file_add (fm, &template);
     931             : 
     932           5 :   pm->is_configured = true;
     933             : 
     934           5 :   return 0;
     935             : }
     936             : 
     937        7306 : VLIB_CONFIG_FUNCTION (punt_config, "punt");
     938             : 
     939             : /*
     940             :  * fd.io coding-style-patch-verification: ON
     941             :  *
     942             :  * Local Variables:
     943             :  * eval: (c-set-style "gnu")
     944             :  * End:
     945             :  */

Generated by: LCOV version 1.14