LCOV - code coverage report
Current view: top level - plugins/dhcp - dhcp4_proxy_node.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 344 499 68.9 %
Date: 2023-10-26 01:39:38 Functions: 22 30 73.3 %

          Line data    Source code
       1             : /*
       2             :  * proxy_node.c: dhcp proxy node processing
       3             :  *
       4             :  * Copyright (c) 2013 Cisco and/or its affiliates.
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : 
      18             : #include <vlib/vlib.h>
      19             : #include <dhcp/dhcp_proxy.h>
      20             : #include <dhcp/client.h>
      21             : #include <vnet/fib/ip4_fib.h>
      22             : 
      23             : static char *dhcp_proxy_error_strings[] = {
      24             : #define dhcp_proxy_error(n,s) s,
      25             : #include <dhcp/dhcp4_proxy_error.def>
      26             : #undef dhcp_proxy_error
      27             : };
      28             : 
      29             : #define foreach_dhcp_proxy_to_server_input_next \
      30             :   _ (DROP, "error-drop")                      \
      31             :   _ (LOOKUP, "ip4-lookup")                    \
      32             :   _ (SEND_TO_CLIENT, "dhcp-proxy-to-client")
      33             : 
      34             : typedef enum
      35             : {
      36             : #define _(s,n) DHCP_PROXY_TO_SERVER_INPUT_NEXT_##s,
      37             :   foreach_dhcp_proxy_to_server_input_next
      38             : #undef _
      39             :     DHCP_PROXY_TO_SERVER_INPUT_N_NEXT,
      40             : } dhcp_proxy_to_server_input_next_t;
      41             : 
      42             : typedef struct
      43             : {
      44             :   /* 0 => to server, 1 => to client */
      45             :   int which;
      46             :   ip4_address_t trace_ip4_address;
      47             :   u32 error;
      48             :   u32 sw_if_index;
      49             :   u32 original_sw_if_index;
      50             : 
      51             :   /* enough space for the DHCP header plus some options */
      52             :   u8 packet_data[2 * sizeof (dhcp_header_t)];
      53             : }
      54             : dhcp_proxy_trace_t;
      55             : 
      56             : #define VPP_DHCP_OPTION82_SUB1_SIZE   6
      57             : #define VPP_DHCP_OPTION82_SUB5_SIZE   6
      58             : #define VPP_DHCP_OPTION82_VSS_SIZE    12
      59             : #define VPP_DHCP_OPTION82_SIZE (VPP_DHCP_OPTION82_SUB1_SIZE + \
      60             :                                 VPP_DHCP_OPTION82_SUB5_SIZE + \
      61             :                                 VPP_DHCP_OPTION82_VSS_SIZE +3)
      62             : 
      63             : static vlib_node_registration_t dhcp_proxy_to_server_node;
      64             : static vlib_node_registration_t dhcp_proxy_to_client_node;
      65             : 
      66             : static u8 *
      67           3 : format_dhcp_proxy_trace (u8 * s, va_list * args)
      68             : {
      69           3 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      70           3 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      71           3 :   dhcp_proxy_trace_t *t = va_arg (*args, dhcp_proxy_trace_t *);
      72             : 
      73           3 :   if (t->which == 0)
      74           0 :     s = format (s, "DHCP proxy: sent to server %U\n",
      75             :                 format_ip4_address, &t->trace_ip4_address, t->error);
      76             :   else
      77           3 :     s = format (s, "DHCP proxy: broadcast to client from %U\n",
      78             :                 format_ip4_address, &t->trace_ip4_address);
      79             : 
      80           3 :   if (t->error != (u32) ~ 0)
      81           3 :     s = format (s, "  error: %s\n", dhcp_proxy_error_strings[t->error]);
      82             : 
      83           3 :   s = format (s, "  original_sw_if_index: %d, sw_if_index: %d\n",
      84             :               t->original_sw_if_index, t->sw_if_index);
      85           3 :   s = format (s, "  %U",
      86           3 :               format_dhcp_header, t->packet_data, sizeof (t->packet_data));
      87             : 
      88           3 :   return s;
      89             : }
      90             : 
      91             : static u8 *
      92           0 : format_dhcp_proxy_header_with_length (u8 * s, va_list * args)
      93             : {
      94           0 :   dhcp_header_t *h = va_arg (*args, dhcp_header_t *);
      95           0 :   u32 max_header_bytes = va_arg (*args, u32);
      96             :   u32 header_bytes;
      97             : 
      98           0 :   header_bytes = sizeof (h[0]);
      99           0 :   if (max_header_bytes != 0 && header_bytes > max_header_bytes)
     100           0 :     return format (s, "dhcp header truncated");
     101             : 
     102           0 :   s = format (s, "DHCP Proxy");
     103             : 
     104           0 :   return s;
     105             : }
     106             : 
     107             : static uword
     108          13 : dhcp_proxy_to_server_input (vlib_main_t * vm,
     109             :                             vlib_node_runtime_t * node,
     110             :                             vlib_frame_t * from_frame)
     111             : {
     112             :   u32 n_left_from, next_index, *from, *to_next;
     113          13 :   dhcp_proxy_main_t *dpm = &dhcp_proxy_main;
     114          13 :   from = vlib_frame_vector_args (from_frame);
     115          13 :   n_left_from = from_frame->n_vectors;
     116          13 :   u32 pkts_to_server = 0, pkts_to_client = 0, pkts_no_server = 0;
     117          13 :   u32 pkts_no_interface_address = 0;
     118          13 :   u32 pkts_too_big = 0;
     119          13 :   ip4_main_t *im = &ip4_main;
     120             : 
     121          13 :   next_index = node->cached_next_index;
     122             : 
     123          26 :   while (n_left_from > 0)
     124             :     {
     125             :       u32 n_left_to_next;
     126             : 
     127          13 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     128             : 
     129          27 :       while (n_left_from > 0 && n_left_to_next > 0)
     130             :         {
     131             :           u32 bi0;
     132             :           vlib_buffer_t *b0;
     133             :           udp_header_t *u0;
     134             :           dhcp_header_t *h0;
     135             :           ip4_header_t *ip0;
     136             :           u32 next0;
     137             :           u32 old0, new0;
     138             :           ip_csum_t sum0;
     139          14 :           u32 error0 = (u32) ~ 0;
     140          14 :           u32 sw_if_index = 0;
     141          14 :           u32 original_sw_if_index = 0;
     142             :           u32 fib_index;
     143             :           dhcp_proxy_t *proxy;
     144             :           dhcp_server_t *server;
     145             :           u32 rx_sw_if_index;
     146             :           dhcp_option_t *o, *end;
     147          14 :           u32 len = 0;
     148          14 :           u8 is_discover = 0;
     149             :           int space_left;
     150             : 
     151          14 :           bi0 = from[0];
     152          14 :           from += 1;
     153          14 :           n_left_from -= 1;
     154             : 
     155          14 :           b0 = vlib_get_buffer (vm, bi0);
     156             : 
     157          14 :           h0 = vlib_buffer_get_current (b0);
     158             : 
     159             :           /*
     160             :            * udp_local hands us the DHCP header, need udp hdr,
     161             :            * ip hdr to relay to server
     162             :            */
     163          14 :           vlib_buffer_advance (b0, -(sizeof (*u0)));
     164          14 :           u0 = vlib_buffer_get_current (b0);
     165             : 
     166             :           /* This blows. Return traffic has src_port = 67, dst_port = 67 */
     167          14 :           if (u0->src_port ==
     168          14 :               clib_net_to_host_u16 (UDP_DST_PORT_dhcp_to_server))
     169             :             {
     170           5 :               vlib_buffer_advance (b0, sizeof (*u0));
     171           5 :               next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_SEND_TO_CLIENT;
     172           5 :               error0 = 0;
     173           5 :               pkts_to_client++;
     174           5 :               goto do_enqueue;
     175             :             }
     176             : 
     177           9 :           rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     178           9 :           fib_index = im->fib_index_by_sw_if_index[rx_sw_if_index];
     179           9 :           proxy = dhcp_get_proxy (dpm, fib_index, FIB_PROTOCOL_IP4);
     180             : 
     181           9 :           if (PREDICT_FALSE (NULL == proxy))
     182             :             {
     183           0 :               error0 = DHCP_PROXY_ERROR_NO_SERVER;
     184           0 :               next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP;
     185           0 :               pkts_no_server++;
     186           0 :               goto do_trace;
     187             :             }
     188             : 
     189           9 :           if (!vlib_buffer_chain_linearize (vm, b0))
     190             :             {
     191           0 :               error0 = DHCP_PROXY_ERROR_PKT_TOO_BIG;
     192           0 :               next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP;
     193           0 :               pkts_too_big++;
     194           0 :               goto do_trace;
     195             :             }
     196           9 :           space_left = vlib_buffer_space_left_at_end (vm, b0);
     197             :           /* cant parse chains...
     198             :            * and we need some space for option 82*/
     199           9 :           if ((b0->flags & VLIB_BUFFER_NEXT_PRESENT) != 0 ||
     200             :               space_left < VPP_DHCP_OPTION82_SIZE)
     201             :             {
     202           0 :               error0 = DHCP_PROXY_ERROR_PKT_TOO_BIG;
     203           0 :               next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP;
     204           0 :               pkts_too_big++;
     205           0 :               goto do_trace;
     206             :             }
     207             : 
     208           9 :           server = &proxy->dhcp_servers[0];
     209           9 :           vlib_buffer_advance (b0, -(sizeof (*ip0)));
     210           9 :           ip0 = vlib_buffer_get_current (b0);
     211             : 
     212             :           /* disable UDP checksum */
     213           9 :           u0->checksum = 0;
     214           9 :           sum0 = ip0->checksum;
     215           9 :           old0 = ip0->dst_address.as_u32;
     216           9 :           new0 = server->dhcp_server.ip4.as_u32;
     217           9 :           ip0->dst_address.as_u32 = server->dhcp_server.ip4.as_u32;
     218           9 :           sum0 = ip_csum_update (sum0, old0, new0,
     219             :                                  ip4_header_t /* structure */ ,
     220             :                                  dst_address /* changed member */ );
     221           9 :           ip0->checksum = ip_csum_fold (sum0);
     222             : 
     223           9 :           sum0 = ip0->checksum;
     224           9 :           old0 = ip0->src_address.as_u32;
     225           9 :           new0 = proxy->dhcp_src_address.ip4.as_u32;
     226           9 :           ip0->src_address.as_u32 = new0;
     227           9 :           sum0 = ip_csum_update (sum0, old0, new0,
     228             :                                  ip4_header_t /* structure */ ,
     229             :                                  src_address /* changed member */ );
     230           9 :           ip0->checksum = ip_csum_fold (sum0);
     231             : 
     232             :           /* Send to DHCP server via the configured FIB */
     233           9 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = server->server_fib_index;
     234             : 
     235           9 :           h0->gateway_ip_address = proxy->dhcp_src_address.ip4;
     236           9 :           pkts_to_server++;
     237             : 
     238           9 :           o = h0->options;
     239           9 :           end = (void *) vlib_buffer_get_tail (b0);
     240             : 
     241             :           /* TLVs are not performance-friendly... */
     242          18 :           while (o->option != DHCP_PACKET_OPTION_END && o < end)
     243             :             {
     244           9 :               if (DHCP_PACKET_OPTION_MSG_TYPE == o->option)
     245             :                 {
     246           9 :                   if (DHCP_PACKET_DISCOVER == o->data[0])
     247             :                     {
     248           8 :                       is_discover = 1;
     249             :                     }
     250             :                 }
     251           9 :               o = (dhcp_option_t *) (o->data + o->length);
     252             :             }
     253             : 
     254           9 :           if (o->option == DHCP_PACKET_OPTION_END && o <= end)
     255           9 :             {
     256           9 :               vnet_main_t *vnm = vnet_get_main ();
     257             :               u16 old_l0, new_l0;
     258           9 :               ip4_address_t _ia0, *ia0 = &_ia0;
     259             :               dhcp_vss_t *vss;
     260             :               vnet_sw_interface_t *swif;
     261             : 
     262           9 :               original_sw_if_index = sw_if_index =
     263           9 :                 vnet_buffer (b0)->sw_if_index[VLIB_RX];
     264           9 :               swif = vnet_get_sw_interface (vnm, sw_if_index);
     265           9 :               if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
     266           0 :                 sw_if_index = swif->unnumbered_sw_if_index;
     267             : 
     268             :               /*
     269             :                * Get the first ip4 address on the [client-side]
     270             :                * RX interface, if not unnumbered. otherwise use
     271             :                * the loopback interface's ip address.
     272             :                */
     273           9 :               ia0 = ip4_interface_first_address (&ip4_main, sw_if_index, 0);
     274             : 
     275           9 :               if (ia0 == 0)
     276             :                 {
     277           0 :                   error0 = DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS;
     278           0 :                   next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP;
     279           0 :                   pkts_no_interface_address++;
     280           0 :                   goto do_trace;
     281             :                 }
     282             : 
     283             :               /* Add option 82 */
     284           9 :               o->option = 82;        /* option 82 */
     285           9 :               o->length = 12;        /* 12 octets to follow */
     286           9 :               o->data[0] = 1;        /* suboption 1, circuit ID (=FIB id) */
     287           9 :               o->data[1] = 4;        /* length of suboption */
     288           9 :               u32 *o_ifid = (u32 *) & o->data[2];
     289           9 :               *o_ifid = clib_host_to_net_u32 (original_sw_if_index);
     290           9 :               o->data[6] = 5;        /* suboption 5 (client RX intfc address) */
     291           9 :               o->data[7] = 4;        /* length 4 */
     292           9 :               u32 *o_addr = (u32 *) & o->data[8];
     293           9 :               *o_addr = ia0->as_u32;
     294           9 :               o->data[12] = DHCP_PACKET_OPTION_END;
     295             : 
     296           9 :               vss = dhcp_get_vss_info (dpm, fib_index, FIB_PROTOCOL_IP4);
     297           9 :               if (vss)
     298             :                 {
     299             :                   u32 id_len;   /* length of VPN ID */
     300             : 
     301           5 :                   if (vss->vss_type == VSS_TYPE_VPN_ID)
     302             :                     {
     303           4 :                       id_len = sizeof (vss->vpn_id); /* vpn_id is 7 bytes */
     304           4 :                       memcpy (&o->data[15], vss->vpn_id, id_len);
     305             :                     }
     306           1 :                   else if (vss->vss_type == VSS_TYPE_ASCII)
     307             :                     {
     308           1 :                       id_len = vec_len (vss->vpn_ascii_id);
     309           1 :                       memcpy (&o->data[15], vss->vpn_ascii_id, id_len);
     310             :                     }
     311             :                   else          /* must be VSS_TYPE_DEFAULT, no VPN ID */
     312           0 :                     id_len = 0;
     313             : 
     314           5 :                   o->data[12] = 151; /* vss suboption */
     315           5 :                   o->data[13] = id_len + 1;  /* length: vss_type + id_len */
     316           5 :                   o->data[14] = vss->vss_type;    /* vss option type */
     317           5 :                   o->data[15 + id_len] = 152;        /* vss control suboption */
     318           5 :                   o->data[16 + id_len] = 0;  /* length */
     319           5 :                   o->data[17 + id_len] = DHCP_PACKET_OPTION_END;     /* "end-of-options" (0xFF) */
     320             :                   /* 5 bytes for suboption headers 151+len, 152+len and 0xFF */
     321           5 :                   o->length += id_len + 5;
     322             :                 }
     323             : 
     324           9 :               len = o->length + 3;
     325           9 :               b0->current_length += len;
     326             :               /* Fix IP header length and checksum */
     327           9 :               old_l0 = ip0->length;
     328           9 :               new_l0 = clib_net_to_host_u16 (old_l0);
     329           9 :               new_l0 += len;
     330           9 :               new_l0 = clib_host_to_net_u16 (new_l0);
     331           9 :               ip0->length = new_l0;
     332           9 :               sum0 = ip0->checksum;
     333           9 :               sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
     334             :                                      length /* changed member */ );
     335           9 :               ip0->checksum = ip_csum_fold (sum0);
     336             : 
     337             :               /* Fix UDP length */
     338           9 :               new_l0 = clib_net_to_host_u16 (u0->length);
     339           9 :               new_l0 += len;
     340           9 :               u0->length = clib_host_to_net_u16 (new_l0);
     341             :             }
     342             :           else
     343             :             {
     344           0 :               vlib_node_increment_counter
     345             :                 (vm, dhcp_proxy_to_server_node.index,
     346             :                  DHCP_PROXY_ERROR_OPTION_82_ERROR, 1);
     347             :             }
     348             : 
     349           9 :           next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP;
     350             : 
     351             :           /*
     352             :            * If we have multiple servers configured and this is the
     353             :            * client's discover message, then send copies to each of
     354             :            * those servers
     355             :            */
     356           9 :           if (is_discover && vec_len (proxy->dhcp_servers) > 1)
     357             :             {
     358             :               u32 ii;
     359             : 
     360           2 :               for (ii = 1; ii < vec_len (proxy->dhcp_servers); ii++)
     361             :                 {
     362             :                   vlib_buffer_t *c0;
     363             :                   u32 ci0;
     364             : 
     365           1 :                   c0 = vlib_buffer_copy (vm, b0);
     366           1 :                   if (c0 == NULL)
     367             :                     {
     368           0 :                       vlib_node_increment_counter
     369             :                         (vm, dhcp_proxy_to_server_node.index,
     370             :                          DHCP_PROXY_ERROR_ALLOC_FAIL, 1);
     371           0 :                       continue;
     372             :                     }
     373           1 :                   ci0 = vlib_get_buffer_index (vm, c0);
     374           1 :                   server = &proxy->dhcp_servers[ii];
     375             : 
     376           1 :                   ip0 = vlib_buffer_get_current (c0);
     377             : 
     378           1 :                   sum0 = ip0->checksum;
     379           1 :                   old0 = ip0->dst_address.as_u32;
     380           1 :                   new0 = server->dhcp_server.ip4.as_u32;
     381           1 :                   ip0->dst_address.as_u32 = server->dhcp_server.ip4.as_u32;
     382           1 :                   sum0 = ip_csum_update (sum0, old0, new0,
     383             :                                          ip4_header_t /* structure */ ,
     384             :                                          dst_address /* changed member */ );
     385           1 :                   ip0->checksum = ip_csum_fold (sum0);
     386             : 
     387           1 :                   to_next[0] = ci0;
     388           1 :                   to_next += 1;
     389           1 :                   n_left_to_next -= 1;
     390             : 
     391           1 :                   vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     392             :                                                    to_next, n_left_to_next,
     393             :                                                    ci0, next0);
     394             : 
     395           1 :                   if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
     396             :                     {
     397             :                       dhcp_proxy_trace_t *tr;
     398             : 
     399           1 :                       tr = vlib_add_trace (vm, node, c0, sizeof (*tr));
     400           1 :                       tr->which = 0; /* to server */
     401           1 :                       tr->error = error0;
     402           1 :                       tr->original_sw_if_index = original_sw_if_index;
     403           1 :                       tr->sw_if_index = sw_if_index;
     404           1 :                       if (next0 == DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP)
     405           1 :                         tr->trace_ip4_address.as_u32 =
     406           1 :                           server->dhcp_server.ip4.as_u32;
     407             : 
     408           1 :                       clib_memcpy_fast (tr->packet_data, h0,
     409             :                                         sizeof (tr->packet_data));
     410             : 
     411             :                     }
     412             : 
     413           1 :                   if (PREDICT_FALSE (0 == n_left_to_next))
     414             :                     {
     415           0 :                       vlib_put_next_frame (vm, node, next_index,
     416             :                                            n_left_to_next);
     417           0 :                       vlib_get_next_frame (vm, node, next_index,
     418             :                                            to_next, n_left_to_next);
     419             :                     }
     420             :                 }
     421             :             }
     422           9 :         do_trace:
     423           9 :           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
     424             :             {
     425           9 :               dhcp_proxy_trace_t *tr = vlib_add_trace (vm, node,
     426             :                                                        b0, sizeof (*tr));
     427           9 :               tr->which = 0; /* to server */
     428           9 :               tr->error = error0;
     429           9 :               tr->original_sw_if_index = original_sw_if_index;
     430           9 :               tr->sw_if_index = sw_if_index;
     431           9 :               if (next0 == DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP)
     432           9 :                 tr->trace_ip4_address.as_u32 =
     433           9 :                   proxy->dhcp_servers[0].dhcp_server.ip4.as_u32;
     434           9 :               clib_memcpy_fast (tr->packet_data, h0,
     435             :                                 sizeof (tr->packet_data));
     436             :             }
     437             : 
     438           0 :         do_enqueue:
     439          14 :           to_next[0] = bi0;
     440          14 :           to_next += 1;
     441          14 :           n_left_to_next -= 1;
     442             : 
     443          14 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     444             :                                            to_next, n_left_to_next,
     445             :                                            bi0, next0);
     446             :         }
     447             : 
     448          13 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     449             :     }
     450          13 :   vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index,
     451             :                                DHCP_PROXY_ERROR_RELAY_TO_CLIENT,
     452             :                                pkts_to_client);
     453          13 :   vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index,
     454             :                                DHCP_PROXY_ERROR_RELAY_TO_SERVER,
     455             :                                pkts_to_server);
     456          13 :   vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index,
     457             :                                DHCP_PROXY_ERROR_NO_SERVER, pkts_no_server);
     458          13 :   vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index,
     459             :                                DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS,
     460             :                                pkts_no_interface_address);
     461          13 :   vlib_node_increment_counter (vm, dhcp_proxy_to_server_node.index,
     462             :                                DHCP_PROXY_ERROR_PKT_TOO_BIG, pkts_too_big);
     463          13 :   return from_frame->n_vectors;
     464             : }
     465             : 
     466             : /* *INDENT-OFF* */
     467      153836 : VLIB_REGISTER_NODE (dhcp_proxy_to_server_node, static) = {
     468             :   .function = dhcp_proxy_to_server_input,
     469             :   .name = "dhcp-proxy-to-server",
     470             :   /* Takes a vector of packets. */
     471             :   .vector_size = sizeof (u32),
     472             : 
     473             :   .n_errors = DHCP_PROXY_N_ERROR,
     474             :   .error_strings = dhcp_proxy_error_strings,
     475             : 
     476             :   .n_next_nodes = DHCP_PROXY_TO_SERVER_INPUT_N_NEXT,
     477             :   .next_nodes = {
     478             : #define _(s,n) [DHCP_PROXY_TO_SERVER_INPUT_NEXT_##s] = n,
     479             :     foreach_dhcp_proxy_to_server_input_next
     480             : #undef _
     481             :   },
     482             : 
     483             :   .format_buffer = format_dhcp_proxy_header_with_length,
     484             :   .format_trace = format_dhcp_proxy_trace,
     485             : #if 0
     486             :   .unformat_buffer = unformat_dhcp_proxy_header,
     487             : #endif
     488             : };
     489             : /* *INDENT-ON* */
     490             : 
     491             : typedef enum
     492             : {
     493             :   DHCP4_PROXY_NEXT_DROP,
     494             :   DHCP4_PROXY_NEXT_TX,
     495             :   DHCP4_PROXY_N_NEXT,
     496             : } dhcp4_next_t;
     497             : 
     498             : static uword
     499          13 : dhcp_proxy_to_client_input (vlib_main_t * vm,
     500             :                             vlib_node_runtime_t * node,
     501             :                             vlib_frame_t * from_frame)
     502             : {
     503             :   u32 n_left_from, *from, *to_next, n_left_to_next;
     504          13 :   ethernet_main_t *em = vnet_get_ethernet_main ();
     505          13 :   dhcp_proxy_main_t *dpm = &dhcp_proxy_main;
     506          13 :   vnet_main_t *vnm = vnet_get_main ();
     507          13 :   ip4_main_t *im = &ip4_main;
     508             :   u32 next_index;
     509             : 
     510          13 :   from = vlib_frame_vector_args (from_frame);
     511          13 :   n_left_from = from_frame->n_vectors;
     512          13 :   next_index = node->cached_next_index;
     513             : 
     514          26 :   while (n_left_from > 0)
     515             :     {
     516          13 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     517             : 
     518          27 :       while (n_left_from > 0 && n_left_to_next > 0)
     519             :         {
     520             :           u32 bi0;
     521             :           vlib_buffer_t *b0;
     522             :           udp_header_t *u0;
     523             :           dhcp_header_t *h0;
     524          14 :           ip4_header_t *ip0 = 0;
     525          14 :           ip4_address_t *ia0 = 0;
     526             :           u32 old0, new0;
     527             :           ip_csum_t sum0;
     528             :           ethernet_interface_t *ei0;
     529             :           ethernet_header_t *mac0;
     530             :           vnet_hw_interface_t *hi0;
     531          14 :           u32 sw_if_index = ~0;
     532             :           vnet_sw_interface_t *si0;
     533          14 :           u32 inner_vlan = (u32) ~ 0;
     534          14 :           u32 outer_vlan = (u32) ~ 0;
     535          14 :           u32 error0 = (u32) ~ 0;
     536             :           vnet_sw_interface_t *swif;
     537             :           u32 fib_index;
     538             :           dhcp_proxy_t *proxy;
     539             :           dhcp_server_t *server;
     540          14 :           u32 original_sw_if_index = (u32) ~ 0;
     541          14 :           dhcp4_next_t next0 = DHCP4_PROXY_NEXT_TX;
     542          14 :           ip4_address_t relay_addr = {
     543             :             .as_u32 = 0,
     544             :           };
     545             : 
     546          14 :           bi0 = to_next[0] = from[0];
     547          14 :           from += 1;
     548          14 :           to_next += 1;
     549          14 :           n_left_from -= 1;
     550          14 :           n_left_to_next -= 1;
     551             : 
     552          14 :           b0 = vlib_get_buffer (vm, bi0);
     553          14 :           h0 = vlib_buffer_get_current (b0);
     554             : 
     555             :           /*
     556             :            * udp_local hands us the DHCP header, need udp hdr,
     557             :            * ip hdr to relay to client
     558             :            */
     559          14 :           vlib_buffer_advance (b0, -(sizeof (*u0)));
     560          14 :           u0 = vlib_buffer_get_current (b0);
     561             : 
     562          14 :           vlib_buffer_advance (b0, -(sizeof (*ip0)));
     563          14 :           ip0 = vlib_buffer_get_current (b0);
     564             : 
     565             :           /* Consumed by dhcp client code? */
     566          14 :           if (dhcp_client_for_us (bi0, b0, ip0, u0, h0))
     567             :             {
     568           9 :               error0 = DHCP_PROXY_ERROR_FOR_US;
     569           9 :               goto drop_packet;
     570             :             }
     571             : 
     572             :           // if (1 /* dpm->insert_option_82 */ )
     573             :           /* linearize needed to "unclone" and scan options */
     574           5 :           int rv = vlib_buffer_chain_linearize (vm, b0);
     575           5 :           if ((b0->flags & VLIB_BUFFER_NEXT_PRESENT) != 0 || !rv)
     576             :             {
     577           0 :               error0 = DHCP_PROXY_ERROR_PKT_TOO_BIG;
     578           0 :               goto drop_packet;
     579             :             }
     580             : 
     581           5 :           dhcp_option_t *o = h0->options, *end =
     582           5 :             (void *) vlib_buffer_get_tail (b0);
     583             : 
     584             :           /* Parse through TLVs looking for option 82.
     585             :              The circuit-ID is the FIB number we need
     586             :              to track down the client-facing interface */
     587             : 
     588          15 :           while (o->option != DHCP_PACKET_OPTION_END && o < end)
     589             :             {
     590          10 :               if (o->option == 82)
     591             :                 {
     592           5 :                   u32 vss_exist = 0;
     593           5 :                   u32 vss_ctrl = 0;
     594           5 :                   dhcp_option_t *sub = (dhcp_option_t *) & o->data[0];
     595           5 :                   dhcp_option_t *subend =
     596           5 :                     (dhcp_option_t *) (o->data + o->length);
     597          19 :                   while (sub->option != DHCP_PACKET_OPTION_END
     598          14 :                          && sub < subend)
     599             :                     {
     600             :                       /* If this is one of ours, it will have
     601             :                          total length 12, circuit-id suboption type,
     602             :                          and the sw_if_index */
     603          14 :                       if (sub->option == 1 && sub->length == 4)
     604             :                         {
     605           5 :                           sw_if_index = ((sub->data[0] << 24) |
     606           5 :                                          (sub->data[1] << 16) |
     607           5 :                                          (sub->data[2] << 8) |
     608           5 :                                          (sub->data[3]));
     609             :                         }
     610           9 :                       else if (sub->option == 5 && sub->length == 4)
     611             :                         {
     612           5 :                           relay_addr.as_u8[0] = sub->data[0];
     613           5 :                           relay_addr.as_u8[1] = sub->data[1];
     614           5 :                           relay_addr.as_u8[2] = sub->data[2];
     615           5 :                           relay_addr.as_u8[3] = sub->data[3];
     616             :                         }
     617           4 :                       else if (sub->option == 151 &&
     618           2 :                                sub->length == 7 && sub->data[0] == 1)
     619           0 :                         vss_exist = 1;
     620           4 :                       else if (sub->option == 152 && sub->length == 0)
     621           2 :                         vss_ctrl = 1;
     622          14 :                       sub = (dhcp_option_t *) (sub->data + sub->length);
     623             :                     }
     624           5 :                   if (vss_ctrl && vss_exist)
     625           0 :                     vlib_node_increment_counter
     626             :                       (vm, dhcp_proxy_to_client_node.index,
     627             :                        DHCP_PROXY_ERROR_OPTION_82_VSS_NOT_PROCESSED, 1);
     628             : 
     629             :                 }
     630          10 :               o = (dhcp_option_t *) (o->data + o->length);
     631             :             }
     632             : 
     633           5 :           if (sw_if_index == (u32) ~ 0)
     634             :             {
     635           0 :               error0 = DHCP_PROXY_ERROR_NO_OPTION_82;
     636             : 
     637          11 :             drop_packet:
     638          11 :               vlib_node_increment_counter (vm,
     639             :                                            dhcp_proxy_to_client_node.index,
     640             :                                            error0, 1);
     641          11 :               b0->error = node->errors[error0];
     642          11 :               next0 = DHCP4_PROXY_NEXT_DROP;
     643          11 :               goto do_trace;
     644             :             }
     645             : 
     646           5 :           if (relay_addr.as_u32 == 0)
     647             :             {
     648           0 :               error0 = DHCP_PROXY_ERROR_BAD_OPTION_82_ADDR;
     649           0 :               goto drop_packet;
     650             :             }
     651             : 
     652           5 :           if (sw_if_index >= vec_len (im->fib_index_by_sw_if_index))
     653             :             {
     654           1 :               error0 = DHCP_PROXY_ERROR_BAD_OPTION_82_ITF;
     655           1 :               goto drop_packet;
     656             :             }
     657             : 
     658           4 :           fib_index = im->fib_index_by_sw_if_index[sw_if_index];
     659           4 :           proxy = dhcp_get_proxy (dpm, fib_index, FIB_PROTOCOL_IP4);
     660             : 
     661           4 :           if (PREDICT_FALSE (NULL == proxy))
     662             :             {
     663           0 :               error0 = DHCP_PROXY_ERROR_NO_SERVER;
     664           0 :               goto drop_packet;
     665             :             }
     666             : 
     667           5 :           vec_foreach (server, proxy->dhcp_servers)
     668             :           {
     669           5 :             if (ip0->src_address.as_u32 == server->dhcp_server.ip4.as_u32)
     670             :               {
     671           4 :                 goto server_found;
     672             :               }
     673             :           }
     674             : 
     675           0 :           error0 = DHCP_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS;
     676           0 :           goto drop_packet;
     677             : 
     678           4 :         server_found:
     679           4 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index;
     680             : 
     681           4 :           swif = vnet_get_sw_interface (vnm, sw_if_index);
     682           4 :           original_sw_if_index = sw_if_index;
     683           4 :           if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
     684           0 :             sw_if_index = swif->unnumbered_sw_if_index;
     685             : 
     686           4 :           ia0 = ip4_interface_first_address (&ip4_main, sw_if_index, 0);
     687           4 :           if (ia0 == 0)
     688             :             {
     689           0 :               error0 = DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS;
     690           0 :               goto drop_packet;
     691             :             }
     692             : 
     693           4 :           if (relay_addr.as_u32 != ia0->as_u32)
     694             :             {
     695           1 :               error0 = DHCP_PROXY_ERROR_BAD_YIADDR;
     696           1 :               goto drop_packet;
     697             :             }
     698             : 
     699           3 :           u0->checksum = 0;
     700           3 :           u0->dst_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcp_to_client);
     701           3 :           sum0 = ip0->checksum;
     702           3 :           old0 = ip0->dst_address.as_u32;
     703           3 :           new0 = 0xFFFFFFFF;
     704           3 :           ip0->dst_address.as_u32 = new0;
     705             :           sum0 =
     706           3 :             ip_csum_update (sum0, old0, new0, ip4_header_t /* structure */ ,
     707             :                             dst_address /* offset of changed member */ );
     708           3 :           ip0->checksum = ip_csum_fold (sum0);
     709             : 
     710           3 :           sum0 = ip0->checksum;
     711           3 :           old0 = ip0->src_address.as_u32;
     712           3 :           new0 = ia0->as_u32;
     713           3 :           ip0->src_address.as_u32 = new0;
     714             :           sum0 =
     715           3 :             ip_csum_update (sum0, old0, new0, ip4_header_t /* structure */ ,
     716             :                             src_address /* offset of changed member */ );
     717           3 :           ip0->checksum = ip_csum_fold (sum0);
     718             : 
     719           3 :           vlib_buffer_advance (b0, -(sizeof (ethernet_header_t)));
     720           3 :           si0 = vnet_get_sw_interface (vnm, original_sw_if_index);
     721           3 :           if (si0->type == VNET_SW_INTERFACE_TYPE_SUB)
     722             :             {
     723           0 :               if (si0->sub.eth.flags.one_tag == 1)
     724             :                 {
     725           0 :                   vlib_buffer_advance (b0, -4 /* space for 1 VLAN tag */ );
     726           0 :                   outer_vlan = (si0->sub.eth.outer_vlan_id << 16) | 0x0800;
     727             :                 }
     728           0 :               else if (si0->sub.eth.flags.two_tags == 1)
     729             :                 {
     730           0 :                   vlib_buffer_advance (b0, -8 /* space for 2 VLAN tag */ );
     731           0 :                   outer_vlan = (si0->sub.eth.outer_vlan_id << 16) | 0x8100;
     732           0 :                   inner_vlan = (si0->sub.eth.inner_vlan_id << 16) | 0x0800;
     733             :                 }
     734             :             }
     735             : 
     736           3 :           mac0 = vlib_buffer_get_current (b0);
     737             : 
     738           3 :           hi0 = vnet_get_sup_hw_interface (vnm, original_sw_if_index);
     739           3 :           ei0 = pool_elt_at_index (em->interfaces, hi0->hw_instance);
     740           3 :           clib_memcpy (mac0->src_address, &ei0->address,
     741             :                        sizeof (mac0->src_address));
     742           3 :           clib_memset (mac0->dst_address, 0xff, sizeof (mac0->dst_address));
     743             : 
     744           3 :           if (si0->type == VNET_SW_INTERFACE_TYPE_SUB
     745           0 :               && outer_vlan != (u32) ~ 0)
     746           0 :             {
     747           0 :               mac0->type = (si0->sub.eth.flags.dot1ad == 1) ?
     748           0 :                 clib_net_to_host_u16 (0x88a8) : clib_net_to_host_u16 (0x8100);
     749           0 :               u32 *vlan_tag = (u32 *) (mac0 + 1);
     750           0 :               *vlan_tag = clib_host_to_net_u32 (outer_vlan);
     751           0 :               if (inner_vlan != (u32) ~ 0)
     752             :                 {
     753           0 :                   u32 *inner_vlan_tag = (u32 *) (vlan_tag + 1);
     754           0 :                   *inner_vlan_tag = clib_host_to_net_u32 (inner_vlan);
     755             :                 }
     756             :             }
     757             :           else
     758             :             {
     759           3 :               mac0->type = clib_net_to_host_u16 (0x0800);
     760             :             }
     761             : 
     762          14 :         do_trace:
     763          14 :           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
     764             :             {
     765          14 :               dhcp_proxy_trace_t *tr = vlib_add_trace (vm, node,
     766             :                                                        b0, sizeof (*tr));
     767          14 :               tr->which = 1; /* to client */
     768          14 :               tr->trace_ip4_address.as_u32 = ia0 ? ia0->as_u32 : 0;
     769          14 :               tr->error = error0;
     770          14 :               tr->original_sw_if_index = original_sw_if_index;
     771          14 :               tr->sw_if_index = sw_if_index;
     772          14 :               clib_memcpy_fast (tr->packet_data, h0,
     773             :                                 sizeof (tr->packet_data));
     774             :             }
     775             : 
     776          14 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     777             :                                            to_next, n_left_to_next,
     778             :                                            bi0, next0);
     779             :         }
     780          13 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     781             :     }
     782             : 
     783          13 :   return from_frame->n_vectors;
     784             : }
     785             : 
     786             : /* *INDENT-OFF* */
     787      153836 : VLIB_REGISTER_NODE (dhcp_proxy_to_client_node, static) = {
     788             :   .function = dhcp_proxy_to_client_input,
     789             :   .name = "dhcp-proxy-to-client",
     790             :   /* Takes a vector of packets. */
     791             :   .vector_size = sizeof (u32),
     792             : 
     793             :   .n_errors = DHCP_PROXY_N_ERROR,
     794             :   .error_strings = dhcp_proxy_error_strings,
     795             :   .format_buffer = format_dhcp_proxy_header_with_length,
     796             :   .format_trace = format_dhcp_proxy_trace,
     797             : #if 0
     798             :   .unformat_buffer = unformat_dhcp_proxy_header,
     799             : #endif
     800             :   .n_next_nodes = DHCP4_PROXY_N_NEXT,
     801             :   .next_nodes = {
     802             :     [DHCP4_PROXY_NEXT_DROP] = "error-drop",
     803             :     [DHCP4_PROXY_NEXT_TX] = "interface-output",
     804             :   },
     805             : };
     806             : /* *INDENT-ON* */
     807             : 
     808             : void
     809          13 : dhcp_maybe_register_udp_ports (dhcp_port_reg_flags_t ports)
     810             : {
     811          13 :   dhcp_proxy_main_t *dm = &dhcp_proxy_main;
     812          13 :   vlib_main_t *vm = dm->vlib_main;
     813          13 :   int port_regs_diff = dm->udp_ports_registered ^ ports;
     814             : 
     815          13 :   if (!port_regs_diff)
     816          11 :     return;
     817             : 
     818           2 :   if ((port_regs_diff & DHCP_PORT_REG_CLIENT) & ports)
     819           1 :     udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_client,
     820             :                            dhcp_proxy_to_client_node.index, 1 /* is_ip4 */ );
     821             : 
     822           2 :   if ((port_regs_diff & DHCP_PORT_REG_SERVER) & ports)
     823           1 :     udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_server,
     824             :                            dhcp_proxy_to_server_node.index, 1 /* is_ip4 */ );
     825             : 
     826           2 :   dm->udp_ports_registered |= ports;
     827             : }
     828             : 
     829             : static clib_error_t *
     830         575 : dhcp4_proxy_init (vlib_main_t * vm)
     831             : {
     832         575 :   dhcp_proxy_main_t *dm = &dhcp_proxy_main;
     833             :   vlib_node_t *error_drop_node;
     834             : 
     835         575 :   error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
     836         575 :   dm->error_drop_node_index = error_drop_node->index;
     837         575 :   dm->vlib_main = vm;
     838             : 
     839         575 :   return 0;
     840             : }
     841             : 
     842             : 
     843        1151 : VLIB_INIT_FUNCTION (dhcp4_proxy_init);
     844             : 
     845             : int
     846           8 : dhcp4_proxy_set_server (ip46_address_t * addr,
     847             :                         ip46_address_t * src_addr,
     848             :                         u32 rx_table_id, u32 server_table_id, int is_del)
     849             : {
     850           8 :   u32 rx_fib_index = 0;
     851           8 :   int rc = 0;
     852             : 
     853           8 :   const fib_prefix_t all_1s = {
     854             :     .fp_len = 32,
     855             :     .fp_addr.ip4.as_u32 = 0xffffffff,
     856             :     .fp_proto = FIB_PROTOCOL_IP4,
     857             :   };
     858             : 
     859           8 :   if (ip46_address_is_zero (addr))
     860           0 :     return VNET_API_ERROR_INVALID_DST_ADDRESS;
     861             : 
     862           8 :   if (ip46_address_is_zero (src_addr))
     863           0 :     return VNET_API_ERROR_INVALID_SRC_ADDRESS;
     864             : 
     865           8 :   dhcp_maybe_register_udp_ports (DHCP_PORT_REG_CLIENT | DHCP_PORT_REG_SERVER);
     866             : 
     867           8 :   rx_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
     868             :                                                     rx_table_id,
     869             :                                                     FIB_SOURCE_DHCP);
     870             : 
     871           8 :   if (is_del)
     872             :     {
     873           4 :       if (dhcp_proxy_server_del (FIB_PROTOCOL_IP4, rx_fib_index,
     874             :                                  addr, server_table_id))
     875             :         {
     876           3 :           fib_table_entry_special_remove (rx_fib_index,
     877             :                                           &all_1s, FIB_SOURCE_DHCP);
     878           3 :           fib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_DHCP);
     879             :         }
     880             :     }
     881             :   else
     882             :     {
     883           4 :       if (dhcp_proxy_server_add (FIB_PROTOCOL_IP4,
     884             :                                  addr, src_addr,
     885             :                                  rx_fib_index, server_table_id))
     886             :         {
     887           3 :           fib_table_entry_special_add (rx_fib_index,
     888             :                                        &all_1s,
     889             :                                        FIB_SOURCE_DHCP, FIB_ENTRY_FLAG_LOCAL);
     890           3 :           fib_table_lock (rx_fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_DHCP);
     891             :         }
     892             :     }
     893           8 :   fib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_DHCP);
     894             : 
     895           8 :   return (rc);
     896             : }
     897             : 
     898             : static clib_error_t *
     899           0 : dhcp4_proxy_set_command_fn (vlib_main_t * vm,
     900             :                             unformat_input_t * input,
     901             :                             vlib_cli_command_t * cmd)
     902             : {
     903             :   ip46_address_t server_addr, src_addr;
     904           0 :   u32 server_table_id = 0, rx_table_id = 0;
     905           0 :   int is_del = 0;
     906           0 :   int set_src = 0, set_server = 0;
     907             : 
     908           0 :   clib_memset (&server_addr, 0, sizeof (server_addr));
     909           0 :   clib_memset (&src_addr, 0, sizeof (src_addr));
     910             : 
     911           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     912             :     {
     913           0 :       if (unformat (input, "server %U",
     914             :                     unformat_ip4_address, &server_addr.ip4))
     915           0 :         set_server = 1;
     916           0 :       else if (unformat (input, "server-fib-id %d", &server_table_id))
     917             :         ;
     918           0 :       else if (unformat (input, "rx-fib-id %d", &rx_table_id))
     919             :         ;
     920           0 :       else if (unformat (input, "src-address %U",
     921             :                          unformat_ip4_address, &src_addr.ip4))
     922           0 :         set_src = 1;
     923           0 :       else if (unformat (input, "delete") || unformat (input, "del"))
     924           0 :         is_del = 1;
     925             :       else
     926             :         break;
     927             :     }
     928             : 
     929           0 :   if (is_del || (set_server && set_src))
     930             :     {
     931             :       int rv;
     932             : 
     933           0 :       rv = dhcp4_proxy_set_server (&server_addr, &src_addr, rx_table_id,
     934             :                                    server_table_id, is_del);
     935           0 :       switch (rv)
     936             :         {
     937           0 :         case 0:
     938           0 :           return 0;
     939             : 
     940           0 :         case VNET_API_ERROR_INVALID_DST_ADDRESS:
     941           0 :           return clib_error_return (0, "Invalid server address");
     942             : 
     943           0 :         case VNET_API_ERROR_INVALID_SRC_ADDRESS:
     944           0 :           return clib_error_return (0, "Invalid src address");
     945             : 
     946           0 :         case VNET_API_ERROR_NO_SUCH_ENTRY:
     947           0 :           return clib_error_return
     948             :             (0, "Fib id %d: no per-fib DHCP server configured", rx_table_id);
     949             : 
     950           0 :         default:
     951           0 :           return clib_error_return (0, "BUG: rv %d", rv);
     952             :         }
     953             :     }
     954             :   else
     955           0 :     return clib_error_return (0, "parse error`%U'",
     956             :                               format_unformat_error, input);
     957             : }
     958             : 
     959             : /* *INDENT-OFF* */
     960      235753 : VLIB_CLI_COMMAND (dhcp_proxy_set_command, static) = {
     961             :   .path = "set dhcp proxy",
     962             :   .short_help = "set dhcp proxy [del] server <ip-addr> src-address <ip-addr> [server-fib-id <n>] [rx-fib-id <n>]",
     963             :   .function = dhcp4_proxy_set_command_fn,
     964             : };
     965             : /* *INDENT-ON* */
     966             : 
     967             : static u8 *
     968           0 : format_dhcp4_proxy_server (u8 * s, va_list * args)
     969             : {
     970           0 :   dhcp_proxy_t *proxy = va_arg (*args, dhcp_proxy_t *);
     971             :   ip4_fib_t *rx_fib, *server_fib;
     972             :   dhcp_server_t *server;
     973             : 
     974           0 :   if (proxy == 0)
     975             :     {
     976           0 :       s = format (s, "%=14s%=16s%s", "RX FIB", "Src Address",
     977             :                   "Servers FIB,Address");
     978           0 :       return s;
     979             :     }
     980             : 
     981           0 :   rx_fib = ip4_fib_get (proxy->rx_fib_index);
     982             : 
     983           0 :   s = format (s, "%=14u%=16U", rx_fib->hash.table_id, format_ip46_address,
     984             :               &proxy->dhcp_src_address, IP46_TYPE_ANY);
     985             : 
     986           0 :   vec_foreach (server, proxy->dhcp_servers)
     987             :   {
     988           0 :     server_fib = ip4_fib_get (server->server_fib_index);
     989           0 :     s = format (s, "%u,%U  ", server_fib->hash.table_id, format_ip46_address,
     990             :                 &server->dhcp_server, IP46_TYPE_ANY);
     991             :   }
     992           0 :   return s;
     993             : }
     994             : 
     995             : static int
     996           0 : dhcp4_proxy_show_walk (dhcp_proxy_t * server, void *ctx)
     997             : {
     998           0 :   vlib_main_t *vm = ctx;
     999             : 
    1000           0 :   vlib_cli_output (vm, "%U", format_dhcp4_proxy_server, server);
    1001             : 
    1002           0 :   return (1);
    1003             : }
    1004             : 
    1005             : static clib_error_t *
    1006           0 : dhcp4_proxy_show_command_fn (vlib_main_t * vm,
    1007             :                              unformat_input_t * input,
    1008             :                              vlib_cli_command_t * cmd)
    1009             : {
    1010           0 :   vlib_cli_output (vm, "%U", format_dhcp4_proxy_server,
    1011             :                    NULL /* header line */ );
    1012             : 
    1013           0 :   dhcp_proxy_walk (FIB_PROTOCOL_IP4, dhcp4_proxy_show_walk, vm);
    1014             : 
    1015           0 :   return (NULL);
    1016             : }
    1017             : 
    1018             : /* *INDENT-OFF* */
    1019      235753 : VLIB_CLI_COMMAND (dhcp_proxy_show_command, static) = {
    1020             :   .path = "show dhcp proxy",
    1021             :   .short_help = "Display dhcp proxy server info",
    1022             :   .function = dhcp4_proxy_show_command_fn,
    1023             : };
    1024             : /* *INDENT-ON* */
    1025             : 
    1026             : static clib_error_t *
    1027           0 : dhcp_option_82_vss_fn (vlib_main_t * vm,
    1028             :                        unformat_input_t * input, vlib_cli_command_t * cmd)
    1029             : {
    1030           0 :   u8 is_del = 0, vss_type = VSS_TYPE_DEFAULT;
    1031           0 :   u32 oui = 0, fib_id = 0, tbl_id = ~0;
    1032           0 :   u8 *vpn_ascii_id = 0;
    1033             : 
    1034           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1035             :     {
    1036           0 :       if (unformat (input, "table %d", &tbl_id))
    1037             :         ;
    1038           0 :       else if (unformat (input, "oui %d", &oui))
    1039           0 :         vss_type = VSS_TYPE_VPN_ID;
    1040           0 :       else if (unformat (input, "vpn-id %d", &fib_id))
    1041           0 :         vss_type = VSS_TYPE_VPN_ID;
    1042           0 :       else if (unformat (input, "vpn-ascii-id %s", &vpn_ascii_id))
    1043           0 :         vss_type = VSS_TYPE_ASCII;
    1044           0 :       else if (unformat (input, "delete") || unformat (input, "del"))
    1045           0 :         is_del = 1;
    1046             :       else
    1047             :         break;
    1048             :     }
    1049             : 
    1050           0 :   if (tbl_id == ~0)
    1051           0 :     return clib_error_return (0, "no table ID specified.");
    1052             : 
    1053           0 :   int rv = dhcp_proxy_set_vss (FIB_PROTOCOL_IP4, tbl_id, vss_type,
    1054             :                                vpn_ascii_id, oui, fib_id, is_del);
    1055           0 :   switch (rv)
    1056             :     {
    1057           0 :     case 0:
    1058           0 :       return 0;
    1059           0 :     case VNET_API_ERROR_NO_SUCH_ENTRY:
    1060           0 :       return clib_error_return (0,
    1061             :                                 "option 82 vss for table %d not found in in pool.",
    1062             :                                 tbl_id);
    1063           0 :     default:
    1064           0 :       return clib_error_return (0, "BUG: rv %d", rv);
    1065             : 
    1066             :     }
    1067             : }
    1068             : 
    1069             : /* *INDENT-OFF* */
    1070      235753 : VLIB_CLI_COMMAND (dhcp_proxy_vss_command,static) = {
    1071             :   .path = "set dhcp option-82 vss",
    1072             :   .short_help = "set dhcp option-82 vss [del] table <table id> [oui <n> vpn-id <n> | vpn-ascii-id <text>]",
    1073             :   .function = dhcp_option_82_vss_fn,
    1074             : };
    1075             : /* *INDENT-ON* */
    1076             : 
    1077             : static clib_error_t *
    1078           0 : dhcp_vss_show_command_fn (vlib_main_t * vm,
    1079             :                           unformat_input_t * input, vlib_cli_command_t * cmd)
    1080             : {
    1081           0 :   dhcp_vss_walk (FIB_PROTOCOL_IP4, dhcp_vss_show_walk, vm);
    1082             : 
    1083           0 :   return (NULL);
    1084             : }
    1085             : 
    1086             : /* *INDENT-OFF* */
    1087      235753 : VLIB_CLI_COMMAND (dhcp_proxy_vss_show_command, static) = {
    1088             :   .path = "show dhcp vss",
    1089             :   .short_help = "show dhcp VSS",
    1090             :   .function = dhcp_vss_show_command_fn,
    1091             : };
    1092             : /* *INDENT-ON* */
    1093             : 
    1094             : static clib_error_t *
    1095           0 : dhcp_option_82_address_show_command_fn (vlib_main_t * vm,
    1096             :                                         unformat_input_t * input,
    1097             :                                         vlib_cli_command_t * cmd)
    1098             : {
    1099           0 :   vnet_main_t *vnm = vnet_get_main ();
    1100           0 :   u32 sw_if_index0 = 0, sw_if_index;
    1101             :   vnet_sw_interface_t *swif;
    1102             :   ip4_address_t *ia0;
    1103             : 
    1104           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1105             :     {
    1106             : 
    1107           0 :       if (unformat (input, "%U",
    1108             :                     unformat_vnet_sw_interface, vnm, &sw_if_index0))
    1109             :         {
    1110           0 :           swif = vnet_get_sw_interface (vnm, sw_if_index0);
    1111           0 :           sw_if_index = (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) ?
    1112           0 :             swif->unnumbered_sw_if_index : sw_if_index0;
    1113           0 :           ia0 = ip4_interface_first_address (&ip4_main, sw_if_index, 0);
    1114           0 :           if (ia0)
    1115             :             {
    1116           0 :               vlib_cli_output (vm, "%=20s%=20s", "interface",
    1117             :                                "source IP address");
    1118             : 
    1119           0 :               vlib_cli_output (vm, "%=20U%=20U",
    1120             :                                format_vnet_sw_if_index_name,
    1121             :                                vnm, sw_if_index0, format_ip4_address, ia0);
    1122             :             }
    1123             :           else
    1124           0 :             vlib_cli_output (vm, "%=34s %=20U",
    1125             :                              "No IPv4 address configured on",
    1126             :                              format_vnet_sw_if_index_name, vnm, sw_if_index);
    1127             :         }
    1128             :       else
    1129           0 :         break;
    1130             :     }
    1131             : 
    1132           0 :   return 0;
    1133             : }
    1134             : 
    1135             : /* *INDENT-OFF* */
    1136      235753 : VLIB_CLI_COMMAND (dhcp_proxy_address_show_command,static) = {
    1137             :   .path = "show dhcp option-82-address interface",
    1138             :   .short_help = "show dhcp option-82-address interface <interface>",
    1139             :   .function = dhcp_option_82_address_show_command_fn,
    1140             : };
    1141             : /* *INDENT-ON* */
    1142             : 
    1143             : /*
    1144             :  * fd.io coding-style-patch-verification: ON
    1145             :  *
    1146             :  * Local Variables:
    1147             :  * eval: (c-set-style "gnu")
    1148             :  * End:
    1149             :  */

Generated by: LCOV version 1.14