LCOV - code coverage report
Current view: top level - vnet/ethernet - format.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 104 153 68.0 %
Date: 2023-07-05 22:20:52 Functions: 11 13 84.6 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : /*
      16             :  * ethernet_format.c: ethernet formatting/parsing.
      17             :  *
      18             :  * Copyright (c) 2008 Eliot Dresselhaus
      19             :  *
      20             :  * Permission is hereby granted, free of charge, to any person obtaining
      21             :  * a copy of this software and associated documentation files (the
      22             :  * "Software"), to deal in the Software without restriction, including
      23             :  * without limitation the rights to use, copy, modify, merge, publish,
      24             :  * distribute, sublicense, and/or sell copies of the Software, and to
      25             :  * permit persons to whom the Software is furnished to do so, subject to
      26             :  * the following conditions:
      27             :  *
      28             :  * The above copyright notice and this permission notice shall be
      29             :  * included in all copies or substantial portions of the Software.
      30             :  *
      31             :  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      32             :  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      33             :  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      34             :  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      35             :  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
      36             :  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
      37             :  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      38             :  */
      39             : 
      40             : #include <vlib/vlib.h>
      41             : #include <vnet/ethernet/ethernet.h>
      42             : 
      43             : u8 *
      44     1894960 : format_ethernet_address (u8 * s, va_list * args)
      45             : {
      46     1894960 :   ethernet_main_t *em = &ethernet_main;
      47     1894960 :   u8 *a = va_arg (*args, u8 *);
      48             : 
      49     1894960 :   if (em->format_ethernet_address_16bit)
      50           0 :     return format (s, "%02x%02x.%02x%02x.%02x%02x",
      51           0 :                    a[0], a[1], a[2], a[3], a[4], a[5]);
      52             :   else
      53     1894960 :     return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
      54     1894960 :                    a[0], a[1], a[2], a[3], a[4], a[5]);
      55             : }
      56             : 
      57             : u8 *
      58           0 : format_mac_address (u8 * s, va_list * args)
      59             : {
      60           0 :   return (format_ethernet_address (s, args));
      61             : }
      62             : 
      63             : u8 *
      64      912412 : format_ethernet_type (u8 * s, va_list * args)
      65             : {
      66      912412 :   ethernet_type_t type = va_arg (*args, u32);
      67      912412 :   ethernet_main_t *em = &ethernet_main;
      68      912412 :   ethernet_type_info_t *t = ethernet_get_type_info (em, type);
      69             : 
      70      912412 :   if (t)
      71      911515 :     s = format (s, "%s", t->name);
      72             :   else
      73         897 :     s = format (s, "0x%04x", type);
      74             : 
      75      912412 :   return s;
      76             : }
      77             : 
      78             : u8 *
      79       15523 : format_ethernet_vlan_tci (u8 * s, va_list * va)
      80             : {
      81       15523 :   u32 vlan_tci = va_arg (*va, u32);
      82             : 
      83       15523 :   u32 vid = (vlan_tci & 0xfff);
      84       15523 :   u32 cfi = (vlan_tci >> 12) & 1;
      85       15523 :   u32 pri = (vlan_tci >> 13);
      86             : 
      87       15523 :   s = format (s, "%d", vid);
      88       15523 :   if (pri != 0)
      89         417 :     s = format (s, " priority %d", pri);
      90       15523 :   if (cfi != 0)
      91          50 :     s = format (s, " cfi");
      92             : 
      93       15523 :   return s;
      94             : }
      95             : 
      96             : u8 *
      97      904122 : format_ethernet_header_with_length (u8 * s, va_list * args)
      98             : {
      99      904122 :   ethernet_pbb_header_packed_t *ph =
     100             :     va_arg (*args, ethernet_pbb_header_packed_t *);
     101      904122 :   ethernet_max_header_t *m = (ethernet_max_header_t *) ph;
     102      904122 :   u32 max_header_bytes = va_arg (*args, u32);
     103      904122 :   ethernet_main_t *em = &ethernet_main;
     104      904122 :   ethernet_header_t *e = &m->ethernet;
     105             :   ethernet_vlan_header_t *v;
     106      904122 :   ethernet_type_t type = clib_net_to_host_u16 (e->type);
     107             :   ethernet_type_t vlan_type[ARRAY_LEN (m->vlan)];
     108      904122 :   u32 n_vlan = 0, i, header_bytes;
     109             :   u32 indent;
     110             : 
     111      919645 :   while ((type == ETHERNET_TYPE_VLAN || type == ETHERNET_TYPE_DOT1AD
     112      919645 :           || type == ETHERNET_TYPE_DOT1AH) && n_vlan < ARRAY_LEN (m->vlan))
     113             :     {
     114       15523 :       vlan_type[n_vlan] = type;
     115       15523 :       if (type != ETHERNET_TYPE_DOT1AH)
     116             :         {
     117       15523 :           v = m->vlan + n_vlan;
     118       15523 :           type = clib_net_to_host_u16 (v->type);
     119             :         }
     120       15523 :       n_vlan++;
     121             :     }
     122             : 
     123      904122 :   header_bytes = sizeof (e[0]) + n_vlan * sizeof (v[0]);
     124      904122 :   if (max_header_bytes != 0 && header_bytes > max_header_bytes)
     125           0 :     return format (s, "ethernet header truncated");
     126             : 
     127      904122 :   indent = format_get_indent (s);
     128             : 
     129      904122 :   s = format (s, "%U: %U -> %U",
     130             :               format_ethernet_type, type,
     131      904122 :               format_ethernet_address, e->src_address,
     132      904122 :               format_ethernet_address, e->dst_address);
     133             : 
     134      904122 :   if (type != ETHERNET_TYPE_DOT1AH)
     135             :     {
     136      919645 :       for (i = 0; i < n_vlan; i++)
     137             :         {
     138       15523 :           u32 v = clib_net_to_host_u16 (m->vlan[i].priority_cfi_and_id);
     139       15523 :           if (*vlan_type == ETHERNET_TYPE_VLAN)
     140       11917 :             s = format (s, " 802.1q vlan %U", format_ethernet_vlan_tci, v);
     141             :           else
     142        3606 :             s = format (s, " 802.1ad vlan %U", format_ethernet_vlan_tci, v);
     143             :         }
     144             : 
     145      904122 :       if (max_header_bytes != 0 && header_bytes < max_header_bytes)
     146             :         {
     147             :           ethernet_type_info_t *ti;
     148      572287 :           vlib_node_t *node = 0;
     149             : 
     150      572287 :           ti = ethernet_get_type_info (em, type);
     151      572287 :           if (ti && ti->node_index != ~0)
     152      570294 :             node = vlib_get_node (em->vlib_main, ti->node_index);
     153      572287 :           if (node && node->format_buffer)
     154      570060 :             s = format (s, "\n%U%U",
     155             :                         format_white_space, indent,
     156             :                         node->format_buffer, (void *) m + header_bytes,
     157             :                         max_header_bytes - header_bytes);
     158             :         }
     159             :     }
     160             :   else
     161             :     {
     162             :       s =
     163           0 :         format (s, " %s b-tag %04X",
     164           0 :                 (clib_net_to_host_u16 (ph->b_type) ==
     165             :                  ETHERNET_TYPE_DOT1AD) ? "802.1ad" : "",
     166           0 :                 clib_net_to_host_u16 (ph->priority_dei_id));
     167             :       s =
     168           0 :         format (s, " %s i-tag %08X",
     169           0 :                 (clib_net_to_host_u16 (ph->i_type) ==
     170             :                  ETHERNET_TYPE_DOT1AH) ? "802.1ah" : "",
     171             :                 clib_net_to_host_u32 (ph->priority_dei_uca_res_sid));
     172             :     }
     173             : 
     174      904122 :   return s;
     175             : }
     176             : 
     177             : u8 *
     178      331835 : format_ethernet_header (u8 * s, va_list * args)
     179             : {
     180      331835 :   ethernet_max_header_t *m = va_arg (*args, ethernet_max_header_t *);
     181      331835 :   return format (s, "%U", format_ethernet_header_with_length, m, 0);
     182             : }
     183             : 
     184             : /* Parse X:X:X:X:X:X unix style ethernet address. */
     185             : static uword
     186          19 : unformat_ethernet_address_unix (unformat_input_t * input, va_list * args)
     187             : {
     188          19 :   u8 *result = va_arg (*args, u8 *);
     189             :   u32 i, a[6];
     190             : 
     191          19 :   if (!unformat (input, "%_%x:%x:%x:%x:%x:%x%_",
     192             :                  &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]))
     193          16 :     return 0;
     194             : 
     195             :   /* Check range. */
     196          21 :   for (i = 0; i < ARRAY_LEN (a); i++)
     197          18 :     if (a[i] >= (1 << 8))
     198           0 :       return 0;
     199             : 
     200          21 :   for (i = 0; i < ARRAY_LEN (a); i++)
     201          18 :     result[i] = a[i];
     202             : 
     203           3 :   return 1;
     204             : }
     205             : 
     206             : /* Parse X.X.X cisco style ethernet address. */
     207             : static uword
     208          16 : unformat_ethernet_address_cisco (unformat_input_t * input, va_list * args)
     209             : {
     210          16 :   u8 *result = va_arg (*args, u8 *);
     211             :   u32 i, a[3];
     212             : 
     213          16 :   if (!unformat (input, "%_%x.%x.%x%_", &a[0], &a[1], &a[2]))
     214           6 :     return 0;
     215             : 
     216             :   /* Check range. */
     217          40 :   for (i = 0; i < ARRAY_LEN (a); i++)
     218          30 :     if (a[i] >= (1 << 16))
     219           0 :       return 0;
     220             : 
     221          10 :   result[0] = (a[0] >> 8) & 0xff;
     222          10 :   result[1] = (a[0] >> 0) & 0xff;
     223          10 :   result[2] = (a[1] >> 8) & 0xff;
     224          10 :   result[3] = (a[1] >> 0) & 0xff;
     225          10 :   result[4] = (a[2] >> 8) & 0xff;
     226          10 :   result[5] = (a[2] >> 0) & 0xff;
     227             : 
     228          10 :   return 1;
     229             : }
     230             : 
     231             : /* Parse ethernet address; accept either unix or style addresses. */
     232             : uword
     233          19 : unformat_ethernet_address (unformat_input_t * input, va_list * args)
     234             : {
     235          19 :   u8 *result = va_arg (*args, u8 *);
     236          19 :   return (unformat_user (input, unformat_ethernet_address_unix, result)
     237          19 :           || unformat_user (input, unformat_ethernet_address_cisco, result));
     238             : }
     239             : 
     240             : uword
     241           1 : unformat_mac_address (unformat_input_t * input, va_list * args)
     242             : {
     243           1 :   return (unformat_ethernet_address (input, args));
     244             : }
     245             : 
     246             : 
     247             : /* Returns ethernet type as an int in host byte order. */
     248             : uword
     249           6 : unformat_ethernet_type_host_byte_order (unformat_input_t * input,
     250             :                                         va_list * args)
     251             : {
     252           6 :   u16 *result = va_arg (*args, u16 *);
     253           6 :   ethernet_main_t *em = &ethernet_main;
     254             :   int type, i;
     255             : 
     256             :   /* Numeric type. */
     257           6 :   if (unformat (input, "0x%x", &type) || unformat (input, "%d", &type))
     258             :     {
     259           0 :       if (type >= (1 << 16))
     260           0 :         return 0;
     261           0 :       *result = type;
     262           0 :       return 1;
     263             :     }
     264             : 
     265             :   /* Named type. */
     266           6 :   if (unformat_user (input, unformat_vlib_number_by_name,
     267             :                      em->type_info_by_name, &i))
     268             :     {
     269           6 :       ethernet_type_info_t *ti = vec_elt_at_index (em->type_infos, i);
     270           6 :       *result = ti->type;
     271           6 :       return 1;
     272             :     }
     273             : 
     274           0 :   return 0;
     275             : }
     276             : 
     277             : uword
     278           6 : unformat_ethernet_type_net_byte_order (unformat_input_t * input,
     279             :                                        va_list * args)
     280             : {
     281           6 :   u16 *result = va_arg (*args, u16 *);
     282           6 :   if (!unformat_user (input, unformat_ethernet_type_host_byte_order, result))
     283           0 :     return 0;
     284             : 
     285           6 :   *result = clib_host_to_net_u16 ((u16) * result);
     286           6 :   return 1;
     287             : }
     288             : 
     289             : uword
     290           0 : unformat_ethernet_header (unformat_input_t * input, va_list * args)
     291             : {
     292           0 :   u8 **result = va_arg (*args, u8 **);
     293           0 :   ethernet_max_header_t _m, *m = &_m;
     294           0 :   ethernet_header_t *e = &m->ethernet;
     295             :   u16 type;
     296             :   u32 n_vlan;
     297             : 
     298           0 :   if (!unformat (input, "%U: %U -> %U",
     299             :                  unformat_ethernet_type_host_byte_order, &type,
     300             :                  unformat_ethernet_address, &e->src_address,
     301             :                  unformat_ethernet_address, &e->dst_address))
     302           0 :     return 0;
     303             : 
     304           0 :   n_vlan = 0;
     305           0 :   while (unformat (input, "vlan"))
     306             :     {
     307             :       u32 id, priority;
     308             : 
     309           0 :       if (!unformat_user (input, unformat_vlib_number, &id)
     310           0 :           || id >= ETHERNET_N_VLAN)
     311           0 :         return 0;
     312             : 
     313           0 :       if (unformat (input, "priority %d", &priority))
     314             :         {
     315           0 :           if (priority >= 8)
     316           0 :             return 0;
     317           0 :           id |= priority << 13;
     318             :         }
     319             : 
     320           0 :       if (unformat (input, "cfi"))
     321           0 :         id |= 1 << 12;
     322             : 
     323             :       /* Too many vlans given. */
     324           0 :       if (n_vlan >= ARRAY_LEN (m->vlan))
     325           0 :         return 0;
     326             : 
     327           0 :       m->vlan[n_vlan].priority_cfi_and_id = clib_host_to_net_u16 (id);
     328           0 :       n_vlan++;
     329             :     }
     330             : 
     331           0 :   if (n_vlan == 0)
     332           0 :     e->type = clib_host_to_net_u16 (type);
     333             :   else
     334             :     {
     335             :       int i;
     336             : 
     337           0 :       e->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
     338           0 :       for (i = 0; i < n_vlan - 1; i++)
     339           0 :         m->vlan[i].type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
     340           0 :       m->vlan[n_vlan - 1].type = clib_host_to_net_u16 (type);
     341             :     }
     342             : 
     343             :   /* Add header to result. */
     344             :   {
     345             :     void *p;
     346           0 :     u32 n_bytes = sizeof (e[0]) + n_vlan * sizeof (m->vlan[0]);
     347             : 
     348           0 :     vec_add2 (*result, p, n_bytes);
     349           0 :     clib_memcpy (p, m, n_bytes);
     350             :   }
     351             : 
     352           0 :   return 1;
     353             : }
     354             : 
     355             : /*
     356             :  * fd.io coding-style-patch-verification: ON
     357             :  *
     358             :  * Local Variables:
     359             :  * eval: (c-set-style "gnu")
     360             :  * End:
     361             :  */

Generated by: LCOV version 1.14