FD.io VPP  v21.06-3-gbb25fbf28
Vector Packet Processing
lldp_input.c
Go to the documentation of this file.
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 parsing implementation
18  */
19 #include <lldp/lldp_node.h>
20 #include <lldp/lldp_protocol.h>
21 #include <vlibmemory/api.h>
22 
23 typedef struct
24 {
31  u8 data[0]; /* this contains both chassis id (chassis_id_len bytes) and port
32  id (portid_len bytes) */
34 
35 static void
37 {
38  ASSERT (vlib_get_thread_index () == 0);
39 
40  lldp_intf_t *n = lldp_get_intf (&lldp_main, a->hw_if_index);
41  if (!n)
42  {
43  /* LLDP turned off for this interface, ignore the update */
44  return;
45  }
46  const u8 *chassis_id = a->data;
47  const u8 *portid = a->data + a->chassis_id_len;
48 
49  if (n->chassis_id)
50  {
51  _vec_len (n->chassis_id) = 0;
52  }
53  vec_add (n->chassis_id, chassis_id, a->chassis_id_len);
54  n->chassis_id_subtype = a->chassis_id_subtype;
55  if (n->port_id)
56  {
57  _vec_len (n->port_id) = 0;
58  }
59  vec_add (n->port_id, portid, a->portid_len);
60  n->port_id_subtype = a->portid_subtype;
61  n->ttl = a->ttl;
63 }
64 
65 static void
66 lldp_rpc_update_peer (u32 hw_if_index, const u8 * chid, u8 chid_len,
67  u8 chid_subtype, const u8 * portid,
68  u8 portid_len, u8 portid_subtype, u16 ttl)
69 {
70  const size_t data_size =
71  sizeof (lldp_intf_update_t) + chid_len + portid_len;
72  u8 data[data_size];
74  u->hw_if_index = hw_if_index;
75  u->chassis_id_len = chid_len;
76  u->chassis_id_subtype = chid_subtype;
77  u->ttl = ttl;
78  u->portid_len = portid_len;
79  u->portid_subtype = portid_subtype;
80  clib_memcpy (u->data, chid, chid_len);
81  clib_memcpy (u->data + chid_len, portid, portid_len);
83 }
84 
86 lldp_tlv_get_code (const lldp_tlv_t * tlv)
87 {
88  return tlv->head.byte1 >> 1;
89 }
90 
91 void
92 lldp_tlv_set_code (lldp_tlv_t * tlv, lldp_tlv_code_t code)
93 {
94  tlv->head.byte1 = (tlv->head.byte1 & 1) + (code << 1);
95 }
96 
97 u16
98 lldp_tlv_get_length (const lldp_tlv_t * tlv)
99 {
100  return (((u16) (tlv->head.byte1 & 1)) << 8) + tlv->head.byte2;
101 }
102 
103 void
104 lldp_tlv_set_length (lldp_tlv_t * tlv, u16 length)
105 {
106  tlv->head.byte2 = length & ((1 << 8) - 1);
107  if (length > (1 << 8) - 1)
108  {
109  tlv->head.byte1 |= 1;
110  }
111  else
112  {
113  tlv->head.byte1 &= (1 << 8) - 2;
114  }
115 }
116 
118 
119 static int
120 lldp_packet_scan (u32 hw_if_index, const lldp_tlv_t * pkt)
121 {
122  const lldp_tlv_t *tlv = pkt;
123 
124 #define TLV_VIOLATES_PKT_BOUNDARY(pkt, tlv) \
125  (((((u8 *)tlv) + sizeof (lldp_tlv_t)) > ((u8 *)pkt + vec_len (pkt))) || \
126  ((((u8 *)tlv) + lldp_tlv_get_length (tlv)) > ((u8 *)pkt + vec_len (pkt))))
127 
128  /* first tlv is always chassis id, followed by port id and ttl tlvs */
129  if (TLV_VIOLATES_PKT_BOUNDARY (pkt, tlv) ||
130  LLDP_TLV_NAME (chassis_id) != lldp_tlv_get_code (tlv))
131  {
132  return LLDP_ERROR_BAD_TLV;
133  }
134 
135  u16 l = lldp_tlv_get_length (tlv);
136  if (l < STRUCT_SIZE_OF (lldp_chassis_id_tlv_t, subtype) +
138  l > STRUCT_SIZE_OF (lldp_chassis_id_tlv_t, subtype) +
140  {
141  return LLDP_ERROR_BAD_TLV;
142  }
143 
144  u8 chid_subtype = ((lldp_chassis_id_tlv_t *) tlv)->subtype;
145  u8 *chid = ((lldp_chassis_id_tlv_t *) tlv)->id;
146  u8 chid_len = l - STRUCT_SIZE_OF (lldp_chassis_id_tlv_t, subtype);
147 
148  tlv = (lldp_tlv_t *) ((u8 *) tlv + STRUCT_SIZE_OF (lldp_tlv_t, head) + l);
149 
150  if (TLV_VIOLATES_PKT_BOUNDARY (pkt, tlv) ||
151  LLDP_TLV_NAME (port_id) != lldp_tlv_get_code (tlv))
152  {
153  return LLDP_ERROR_BAD_TLV;
154  }
155  l = lldp_tlv_get_length (tlv);
156  if (l < STRUCT_SIZE_OF (lldp_port_id_tlv_t, subtype) +
158  l > STRUCT_SIZE_OF (lldp_chassis_id_tlv_t, subtype) +
160  {
161  return LLDP_ERROR_BAD_TLV;
162  }
163 
164  u8 portid_subtype = ((lldp_port_id_tlv_t *) tlv)->subtype;
165  u8 *portid = ((lldp_port_id_tlv_t *) tlv)->id;
166  u8 portid_len = l - STRUCT_SIZE_OF (lldp_port_id_tlv_t, subtype);
167 
168  tlv = (lldp_tlv_t *) ((u8 *) tlv + STRUCT_SIZE_OF (lldp_tlv_t, head) + l);
169 
170  if (TLV_VIOLATES_PKT_BOUNDARY (pkt, tlv) ||
172  {
173  return LLDP_ERROR_BAD_TLV;
174  }
175  l = lldp_tlv_get_length (tlv);
176  if (l != STRUCT_SIZE_OF (lldp_ttl_tlv_t, ttl))
177  {
178  return LLDP_ERROR_BAD_TLV;
179  }
180  u16 ttl = ntohs (((lldp_ttl_tlv_t *) tlv)->ttl);
181  tlv = (lldp_tlv_t *) ((u8 *) tlv + STRUCT_SIZE_OF (lldp_tlv_t, head) + l);
182  while (!TLV_VIOLATES_PKT_BOUNDARY (pkt, tlv) &&
183  LLDP_TLV_NAME (pdu_end) != lldp_tlv_get_code (tlv))
184  {
185  switch (lldp_tlv_get_code (tlv))
186  {
187 #define F(num, type, str) \
188  case LLDP_TLV_NAME (type): \
189  /* ignore optional TLV */ \
190  break;
192 #undef F
193  default:
194  return LLDP_ERROR_BAD_TLV;
195  }
196  tlv = (lldp_tlv_t *) ((u8 *) tlv + STRUCT_SIZE_OF (lldp_tlv_t, head) +
197  lldp_tlv_get_length (tlv));
198  }
199  /* last tlv is pdu_end */
200  if (TLV_VIOLATES_PKT_BOUNDARY (pkt, tlv) ||
201  LLDP_TLV_NAME (pdu_end) != lldp_tlv_get_code (tlv) ||
202  0 != lldp_tlv_get_length (tlv))
203  {
204  return LLDP_ERROR_BAD_TLV;
205  }
206  lldp_rpc_update_peer (hw_if_index, chid, chid_len, chid_subtype, portid,
207  portid_len, portid_subtype, ttl);
208  return LLDP_ERROR_NONE;
209 }
210 
211 lldp_intf_t *
212 lldp_get_intf (lldp_main_t * lm, u32 hw_if_index)
213 {
214  uword *p = hash_get (lm->intf_by_hw_if_index, hw_if_index);
215 
216  if (p)
217  {
218  return pool_elt_at_index (lm->intfs, p[0]);
219  }
220  return NULL;
221 }
222 
223 lldp_intf_t *
224 lldp_create_intf (lldp_main_t * lm, u32 hw_if_index)
225 {
226 
227  uword *p;
228  lldp_intf_t *n;
229  p = hash_get (lm->intf_by_hw_if_index, hw_if_index);
230 
231  if (p == 0)
232  {
233  pool_get (lm->intfs, n);
234  clib_memset (n, 0, sizeof (*n));
235  n->hw_if_index = hw_if_index;
236  hash_set (lm->intf_by_hw_if_index, n->hw_if_index, n - lm->intfs);
237  }
238  else
239  {
240  n = pool_elt_at_index (lm->intfs, p[0]);
241  }
242  return n;
243 }
244 
245 /*
246  * lldp input routine
247  */
250 {
251  lldp_main_t *lm = &lldp_main;
252  lldp_error_t e;
253 
254  /* find our interface */
257  (b0)->sw_if_index
258  [VLIB_RX]);
259  lldp_intf_t *n = lldp_get_intf (lm, sw_interface->hw_if_index);
260 
261  if (!n)
262  {
263  /* lldp disabled on this interface, we're done */
264  return LLDP_ERROR_DISABLED;
265  }
266 
267  /* Actually scan the packet */
268  e = lldp_packet_scan (sw_interface->hw_if_index,
270 
271  return e;
272 }
273 
274 /*
275  * setup function
276  */
277 static clib_error_t *
279 {
281  lldp_main_t *lm = &lldp_main;
282 
284  return error;
285 
286  lm->vlib_main = vm;
287  lm->vnet_main = vnet_get_main ();
288  lm->msg_tx_hold = 4; /* default value per IEEE 802.1AB-2009 */
289  lm->msg_tx_interval = 30; /* default value per IEEE 802.1AB-2009 */
290 
291  return 0;
292 }
293 
295 
296 /*
297  * fd.io coding-style-patch-verification: ON
298  *
299  * Local Variables:
300  * eval: (c-set-style "gnu")
301  * End:
302  */
LLDP_MIN_CHASS_ID_LEN
#define LLDP_MIN_CHASS_ID_LEN
Definition: lldp_protocol.h:82
lldp_intf::last_heard
f64 last_heard
Definition: lldp_node.h:36
lldp_intf_update_t::hw_if_index
u32 hw_if_index
Definition: lldp_input.c:25
lldp_packet_scan
static int lldp_packet_scan(u32 hw_if_index, const lldp_tlv_t *pkt)
Definition: lldp_input.c:120
api.h
vec_add
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
Definition: vec.h:688
lldp_rpc_update_peer
static void lldp_rpc_update_peer(u32 hw_if_index, const u8 *chid, u8 chid_len, u8 chid_subtype, const u8 *portid, u8 portid_len, u8 portid_subtype, u16 ttl)
Definition: lldp_input.c:66
ntohs
#define ntohs(x)
Definition: af_xdp.bpf.c:29
vnet_sw_interface_t
Definition: interface.h:868
lldp_intf_update_t
Definition: lldp_input.c:23
lldp_main_t::intf_by_hw_if_index
uword * intf_by_hw_if_index
Definition: lldp_node.h:65
clib_memcpy
#define clib_memcpy(d, s, n)
Definition: string.h:197
lldp_intf::chassis_id
u8 * chassis_id
Definition: lldp_node.h:40
lldp_main_t::msg_tx_interval
u16 msg_tx_interval
Definition: lldp_node.h:102
lldp_intf_update_t::chassis_id_subtype
u8 chassis_id_subtype
Definition: lldp_input.c:27
lldp_intf_update_t::portid_len
u8 portid_len
Definition: lldp_input.c:28
pool_elt_at_index
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:553
ttl
u8 ttl
Definition: fib_types.api:26
lldp_intf::port_id
u8 * port_id
Definition: lldp_node.h:41
TLV_VIOLATES_PKT_BOUNDARY
#define TLV_VIOLATES_PKT_BOUNDARY(pkt, tlv)
lldp_main_t::vlib_main
vlib_main_t * vlib_main
Definition: lldp_node.h:80
lldp_tlv_get_code
lldp_tlv_code_t lldp_tlv_get_code(const lldp_tlv_t *tlv)
Definition: lldp_input.c:86
lldp_get_intf
lldp_intf_t * lldp_get_intf(lldp_main_t *lm, u32 hw_if_index)
Definition: lldp_input.c:212
LLDP_TLV_NAME
#define LLDP_TLV_NAME(t)
Definition: lldp_protocol.h:44
u16
unsigned short u16
Definition: types.h:57
vlib_call_init_function
#define vlib_call_init_function(vm, x)
Definition: init.h:259
vm
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
VLIB_RX
@ VLIB_RX
Definition: defs.h:46
vnet_get_sw_interface
static vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
Definition: interface_funcs.h:58
error
Definition: cJSON.c:88
lldp_main_t::msg_tx_hold
u8 msg_tx_hold
Definition: lldp_node.h:93
hash_set
#define hash_set(h, key, value)
Definition: hash.h:255
lldp_main_t
Definition: lldp_node.h:59
lldp_intf::ttl
u16 ttl
Definition: lldp_node.h:42
vnet_buffer
#define vnet_buffer(b)
Definition: buffer.h:437
vnet_get_main
vnet_main_t * vnet_get_main(void)
Definition: pnat_test_stubs.h:56
lldp_rpc_update_peer_cb
static void lldp_rpc_update_peer_cb(const lldp_intf_update_t *a)
Definition: lldp_input.c:36
vlib_get_thread_index
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:208
lldp_create_intf
lldp_intf_t * lldp_create_intf(lldp_main_t *lm, u32 hw_if_index)
Definition: lldp_input.c:224
lldp_tlv_set_length
void lldp_tlv_set_length(lldp_tlv_t *tlv, u16 length)
Definition: lldp_input.c:104
uword
u64 uword
Definition: types.h:112
hash_get
#define hash_get(h, key)
Definition: hash.h:249
lldp_intf_update_t::chassis_id_len
u8 chassis_id_len
Definition: lldp_input.c:26
lldp_template_init
static clib_error_t * lldp_template_init(vlib_main_t *vm)
Definition: lldp_output.c:272
pool_get
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:255
lldp_main
lldp_main_t lldp_main
Definition: lldp_input.c:117
lldp_tlv_set_code
void lldp_tlv_set_code(lldp_tlv_t *tlv, lldp_tlv_code_t code)
Definition: lldp_input.c:92
foreach_lldp_optional_tlv_type
#define foreach_lldp_optional_tlv_type(F)
Definition: lldp_protocol.h:26
lldp_protocol.h
LLDP protocol declarations.
data
u8 data[128]
Definition: ipsec_types.api:92
ASSERT
#define ASSERT(truth)
Definition: error_bootstrap.h:69
lldp_intf_update_t::portid_subtype
u8 portid_subtype
Definition: lldp_input.c:29
u32
unsigned int u32
Definition: types.h:88
VLIB_INIT_FUNCTION
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:172
lldp_tlv_code_t
lldp_tlv_code_t
Definition: lldp_protocol.h:46
vl_api_rpc_call_main_thread
void vl_api_rpc_call_main_thread(void *fp, u8 *data, u32 data_length)
Definition: vlib_api.c:620
lldp_node.h
LLDP global declarations.
lldp_tlv_get_length
u16 lldp_tlv_get_length(const lldp_tlv_t *tlv)
Definition: lldp_input.c:98
lldp_intf::port_id_subtype
lldp_port_id_subtype_t port_id_subtype
Definition: lldp_node.h:43
lldp_intf_update_t::ttl
u16 ttl
Definition: lldp_input.c:30
length
char const int length
Definition: cJSON.h:163
clib_memset
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
vlib_main_t
Definition: main.h:102
F
#define F(num, type, str)
LLDP_MAX_CHASS_ID_LEN
#define LLDP_MAX_CHASS_ID_LEN
Definition: lldp_protocol.h:83
u8
unsigned char u8
Definition: types.h:56
clib_error_t
Definition: clib_error.h:21
a
a
Definition: bitmap.h:544
vlib_buffer_get_current
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:257
vlib_init_function_t
clib_error_t *() vlib_init_function_t(struct vlib_main_t *vm)
Definition: init.h:51
LLDP_MIN_PORT_ID_LEN
#define LLDP_MIN_PORT_ID_LEN
Definition: lldp_protocol.h:111
lldp_intf::hw_if_index
u32 hw_if_index
Definition: lldp_node.h:33
lldp_intf::chassis_id_subtype
lldp_chassis_id_subtype_t chassis_id_subtype
Definition: lldp_node.h:44
vnet_sw_interface_t::hw_if_index
u32 hw_if_index
Definition: interface.h:886
lldp_main_t::intfs
lldp_intf_t * intfs
Definition: lldp_node.h:62
lldp_input
lldp_error_t lldp_input(vlib_main_t *vm, vlib_buffer_t *b0, u32 bi0)
Definition: lldp_input.c:249
vlib_time_now
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:325
sw_if_index
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
STRUCT_SIZE_OF
#define STRUCT_SIZE_OF(t, f)
Definition: clib.h:75
lldp_main_t::vnet_main
vnet_main_t * vnet_main
Definition: lldp_node.h:81
lldp_init
static clib_error_t * lldp_init(vlib_main_t *vm)
Definition: lldp_input.c:278
lldp_intf
Definition: lldp_node.h:30
lldp_intf_update_t::data
u8 data[0]
Definition: lldp_input.c:31
vlib_buffer_t
VLIB buffer representation.
Definition: buffer.h:111
LLDP_MAX_PORT_ID_LEN
#define LLDP_MAX_PORT_ID_LEN
Definition: lldp_protocol.h:112
lldp_error_t
lldp_error_t
Definition: lldp_node.h:119