LCOV - code coverage report
Current view: top level - plugins/lldp - lldp_output.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 13 141 9.2 %
Date: 2023-10-26 01:39:38 Functions: 3 14 21.4 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2011-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             :  * @file
      17             :  * @brief LLDP packet generation implementation
      18             :  */
      19             : #include <lldp/lldp_node.h>
      20             : 
      21             : static void
      22           0 : lldp_build_mgmt_addr_tlv (u8 ** t0p, u8 subtype, u8 addr_len, u8 * addr,
      23             :                           u32 if_index, u8 oid_len, u8 * oid)
      24             : {
      25           0 :   lldp_tlv_t *t = (lldp_tlv_t *) * t0p;
      26             : 
      27           0 :   lldp_tlv_set_code (t, LLDP_TLV_NAME (mgmt_addr));
      28           0 :   t->v[0] = addr_len + 1;    /* address string length */
      29           0 :   t->v[1] = subtype;         /* address subtype */
      30           0 :   clib_memcpy_fast (&(t->v[2]), addr, addr_len); /* address */
      31           0 :   t->v[addr_len + 2] = 2;    /* interface numbering subtype: ifIndex */
      32           0 :   t->v[addr_len + 3] = (if_index >> 24) & 0xFF;    /* interface number */
      33           0 :   t->v[addr_len + 4] = (if_index >> 16) & 0xFF;
      34           0 :   t->v[addr_len + 5] = (if_index >> 8) & 0xFF;
      35           0 :   t->v[addr_len + 6] = (if_index >> 0) & 0xFF;
      36           0 :   t->v[addr_len + 7] = oid_len;      /* OID string length */
      37             : 
      38           0 :   if (oid_len > 0)
      39           0 :     clib_memcpy_fast ((u8 *) & (t->v[addr_len + 8]), oid, oid_len);
      40             : 
      41           0 :   lldp_tlv_set_length (t, addr_len + oid_len + 8);
      42           0 :   *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + addr_len + oid_len + 8;
      43           0 : }
      44             : 
      45             : static void
      46           0 : lldp_add_chassis_id (const vnet_hw_interface_t * hw, u8 ** t0p)
      47             : {
      48           0 :   lldp_chassis_id_tlv_t *t = (lldp_chassis_id_tlv_t *) * t0p;
      49             : 
      50           0 :   lldp_tlv_set_code ((lldp_tlv_t *) t, LLDP_TLV_NAME (chassis_id));
      51           0 :   t->subtype = LLDP_CHASS_ID_SUBTYPE_NAME (mac_addr);
      52             : 
      53           0 :   const size_t addr_len = 6;
      54           0 :   clib_memcpy_fast (&t->id, hw->hw_address, addr_len);
      55           0 :   const size_t len =
      56             :     STRUCT_SIZE_OF (lldp_chassis_id_tlv_t, subtype) + addr_len;
      57           0 :   lldp_tlv_set_length ((lldp_tlv_t *) t, len);
      58           0 :   *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + len;
      59           0 : }
      60             : 
      61             : static void
      62           0 : lldp_add_port_id (const vnet_hw_interface_t * hw, u8 ** t0p)
      63             : {
      64           0 :   lldp_port_id_tlv_t *t = (lldp_port_id_tlv_t *) * t0p;
      65             : 
      66           0 :   lldp_tlv_set_code ((lldp_tlv_t *) t, LLDP_TLV_NAME (port_id));
      67           0 :   t->subtype = LLDP_PORT_ID_SUBTYPE_NAME (intf_name);
      68             : 
      69           0 :   const size_t name_len = vec_len (hw->name);
      70           0 :   clib_memcpy_fast (&t->id, hw->name, name_len);
      71           0 :   const size_t len = STRUCT_SIZE_OF (lldp_port_id_tlv_t, subtype) + name_len;
      72           0 :   lldp_tlv_set_length ((lldp_tlv_t *) t, len);
      73           0 :   *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + len;
      74           0 : }
      75             : 
      76             : static void
      77           0 : lldp_add_ttl (const lldp_main_t * lm, u8 ** t0p, int shutdown)
      78             : {
      79           0 :   lldp_ttl_tlv_t *t = (lldp_ttl_tlv_t *) * t0p;
      80           0 :   lldp_tlv_set_code ((lldp_tlv_t *) t, LLDP_TLV_NAME (ttl));
      81           0 :   if (shutdown)
      82             :     {
      83           0 :       t->ttl = 0;
      84             :     }
      85             :   else
      86             :     {
      87           0 :       if ((size_t) lm->msg_tx_interval * lm->msg_tx_hold + 1 > (1 << 16) - 1)
      88             :         {
      89           0 :           t->ttl = htons ((1 << 16) - 1);
      90             :         }
      91             :       else
      92             :         {
      93           0 :           t->ttl = htons (lm->msg_tx_hold * lm->msg_tx_interval + 1);
      94             :         }
      95             :     }
      96           0 :   const size_t len = STRUCT_SIZE_OF (lldp_ttl_tlv_t, ttl);
      97           0 :   lldp_tlv_set_length ((lldp_tlv_t *) t, len);
      98           0 :   *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + len;
      99           0 : }
     100             : 
     101             : static void
     102           0 : lldp_add_port_desc (const lldp_main_t * lm, lldp_intf_t * n, u8 ** t0p)
     103             : {
     104           0 :   const size_t len = vec_len (n->port_desc);
     105           0 :   if (len)
     106             :     {
     107           0 :       lldp_tlv_t *t = (lldp_tlv_t *) * t0p;
     108           0 :       lldp_tlv_set_code (t, LLDP_TLV_NAME (port_desc));
     109           0 :       lldp_tlv_set_length (t, len);
     110           0 :       clib_memcpy_fast (t->v, n->port_desc, len);
     111           0 :       *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + len;
     112             :     }
     113           0 : }
     114             : 
     115             : static void
     116           0 : lldp_add_sys_name (const lldp_main_t * lm, u8 ** t0p)
     117             : {
     118           0 :   const size_t len = vec_len (lm->sys_name);
     119           0 :   if (len)
     120             :     {
     121           0 :       lldp_tlv_t *t = (lldp_tlv_t *) * t0p;
     122           0 :       lldp_tlv_set_code (t, LLDP_TLV_NAME (sys_name));
     123           0 :       lldp_tlv_set_length (t, len);
     124           0 :       clib_memcpy_fast (t->v, lm->sys_name, len);
     125           0 :       *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + len;
     126             :     }
     127           0 : }
     128             : 
     129             : static void
     130           0 : lldp_add_mgmt_addr (const lldp_intf_t * n, const vnet_hw_interface_t * hw,
     131             :                     u8 ** t0p)
     132             : {
     133           0 :   const size_t len_ip4 = vec_len (n->mgmt_ip4);
     134           0 :   const size_t len_ip6 = vec_len (n->mgmt_ip6);
     135             : 
     136           0 :   if (!(len_ip4 | len_ip6))
     137             :     {
     138             :       /*
     139             :          If no management address is configured, the interface port's MAC
     140             :          address is sent in one TLV.
     141             :        */
     142             : 
     143           0 :       lldp_build_mgmt_addr_tlv (t0p, 1, /* address subtype: Ipv4 */
     144             :                                 6,      /* address string length */
     145             :                                 hw->hw_address,      /* address */
     146             :                                 hw->hw_if_index,     /* if index */
     147           0 :                                 vec_len (n->mgmt_oid),       /* OID length */
     148             :                                 n->mgmt_oid);        /* OID */
     149           0 :       return;
     150             :     }
     151             : 
     152           0 :   if (len_ip4)
     153             :     {
     154           0 :       lldp_build_mgmt_addr_tlv (t0p, 1, /* address subtype: Ipv4 */
     155             :                                 len_ip4,        /* address string length */
     156             :                                 n->mgmt_ip4, /* address */
     157             :                                 hw->hw_if_index,     /* if index */
     158           0 :                                 vec_len (n->mgmt_oid),       /* OID length */
     159             :                                 n->mgmt_oid);        /* OID */
     160             :     }
     161             : 
     162           0 :   if (len_ip6)
     163             :     {
     164           0 :       lldp_build_mgmt_addr_tlv (t0p, 2, /* address subtype: Ipv6 */
     165             :                                 len_ip6,        /* address string length */
     166             :                                 n->mgmt_ip6, /* address */
     167             :                                 hw->hw_if_index,     /* if index */
     168           0 :                                 vec_len (n->mgmt_oid),       /* OID length */
     169             :                                 n->mgmt_oid);        /* OID */
     170             :     }
     171             : }
     172             : 
     173             : static void
     174           0 : lldp_add_pdu_end (u8 ** t0p)
     175             : {
     176           0 :   lldp_tlv_t *t = (lldp_tlv_t *) * t0p;
     177           0 :   lldp_tlv_set_code (t, LLDP_TLV_NAME (pdu_end));
     178           0 :   lldp_tlv_set_length (t, 0);
     179           0 :   *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head);
     180           0 : }
     181             : 
     182             : static void
     183           0 : lldp_add_tlvs (lldp_main_t * lm, vnet_hw_interface_t * hw, u8 ** t0p,
     184             :                int shutdown, lldp_intf_t * n)
     185             : {
     186           0 :   lldp_add_chassis_id (hw, t0p);
     187           0 :   lldp_add_port_id (hw, t0p);
     188           0 :   lldp_add_ttl (lm, t0p, shutdown);
     189           0 :   lldp_add_port_desc (lm, n, t0p);
     190           0 :   lldp_add_sys_name (lm, t0p);
     191           0 :   lldp_add_mgmt_addr (n, hw, t0p);
     192           0 :   lldp_add_pdu_end (t0p);
     193           0 : }
     194             : 
     195             : /*
     196             :  * send a lldp pkt on an ethernet interface
     197             :  */
     198             : void
     199           0 : lldp_send_ethernet (lldp_main_t * lm, lldp_intf_t * n, int shutdown)
     200             : {
     201             :   u32 *to_next;
     202             :   ethernet_header_t *h0;
     203             :   vnet_hw_interface_t *hw;
     204             :   u32 bi0;
     205             :   vlib_buffer_t *b0;
     206             :   u8 *t0;
     207             :   vlib_frame_t *f;
     208           0 :   vlib_main_t *vm = lm->vlib_main;
     209           0 :   vnet_main_t *vnm = lm->vnet_main;
     210             : 
     211             :   /*
     212             :    * see lldp_template_init() to understand what's already painted
     213             :    * into the buffer by the packet template mechanism
     214             :    */
     215           0 :   h0 = vlib_packet_template_get_packet (vm, &lm->packet_template, &bi0);
     216             : 
     217           0 :   if (!h0)
     218           0 :     return;
     219             : 
     220             :   /* Add the interface's ethernet source address */
     221           0 :   hw = vnet_get_hw_interface (vnm, n->hw_if_index);
     222             : 
     223           0 :   clib_memcpy_fast (h0->src_address, hw->hw_address,
     224           0 :                     vec_len (hw->hw_address));
     225             : 
     226           0 :   u8 *data = ((u8 *) h0) + sizeof (*h0);
     227           0 :   t0 = data;
     228             : 
     229             :   /* add TLVs */
     230           0 :   lldp_add_tlvs (lm, hw, &t0, shutdown, n);
     231             : 
     232             :   /* Set the outbound packet length */
     233           0 :   b0 = vlib_get_buffer (vm, bi0);
     234           0 :   b0->current_length = sizeof (*h0) + t0 - data;
     235             : 
     236             :   /* And the outbound interface */
     237           0 :   vnet_buffer (b0)->sw_if_index[VLIB_TX] = hw->sw_if_index;
     238             : 
     239             :   /* And output the packet on the correct interface */
     240           0 :   f = vlib_get_frame_to_node (vm, hw->output_node_index);
     241           0 :   to_next = vlib_frame_vector_args (f);
     242           0 :   to_next[0] = bi0;
     243           0 :   f->n_vectors = 1;
     244             : 
     245           0 :   vlib_put_frame_to_node (vm, hw->output_node_index, f);
     246           0 :   n->last_sent = vlib_time_now (vm);
     247             : }
     248             : 
     249             : void
     250           0 : lldp_delete_intf (lldp_main_t * lm, lldp_intf_t * n)
     251             : {
     252           0 :   if (n)
     253             :     {
     254           0 :       lldp_unschedule_intf (lm, n);
     255           0 :       hash_unset (lm->intf_by_hw_if_index, n->hw_if_index);
     256           0 :       vec_free (n->chassis_id);
     257           0 :       vec_free (n->port_id);
     258           0 :       vec_free (n->port_desc);
     259           0 :       vec_free (n->mgmt_ip4);
     260           0 :       vec_free (n->mgmt_ip6);
     261           0 :       vec_free (n->mgmt_oid);
     262           0 :       pool_put (lm->intfs, n);
     263             :     }
     264           0 : }
     265             : 
     266             : 
     267             : /* 01:80:C2:00:00:0E - propagation constrained to a single
     268             :  * physical link - stopped by all type of bridge */
     269             : const u8 lldp_mac_addr[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x0E };
     270             : 
     271             : static clib_error_t *
     272         575 : lldp_template_init (vlib_main_t * vm)
     273             : {
     274         575 :   lldp_main_t *lm = &lldp_main;
     275             : 
     276             :   /* Create the ethernet lldp packet template */
     277             :   {
     278             :     ethernet_header_t h;
     279             : 
     280         575 :     clib_memset (&h, 0, sizeof (h));
     281             : 
     282         575 :     h.dst_address[0] = lldp_mac_addr[0];
     283         575 :     h.dst_address[1] = lldp_mac_addr[1];
     284         575 :     h.dst_address[2] = lldp_mac_addr[2];
     285         575 :     h.dst_address[3] = lldp_mac_addr[3];
     286         575 :     h.dst_address[4] = lldp_mac_addr[4];
     287         575 :     h.dst_address[5] = lldp_mac_addr[5];
     288             : 
     289             :     /* leave src address blank (fill in at send time) */
     290             : 
     291         575 :     h.type = htons (ETHERNET_TYPE_802_1_LLDP);
     292             : 
     293         575 :     vlib_packet_template_init (vm, &lm->packet_template,
     294             :                                /* data */ &h, sizeof (h),
     295             :                                /* alloc chunk size */ 8, "lldp-ethernet");
     296             :   }
     297             : 
     298         575 :   return 0;
     299             : }
     300             : 
     301        1151 : VLIB_INIT_FUNCTION (lldp_template_init);
     302             : 
     303             : /*
     304             :  * fd.io coding-style-patch-verification: ON
     305             :  *
     306             :  * Local Variables:
     307             :  * eval: (c-set-style "gnu")
     308             :  * End:
     309             :  */

Generated by: LCOV version 1.14