FD.io VPP  v17.01.1-3-gc6833f8
Vector Packet Processing
cdp_periodic.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 #include <vnet/cdp/cdp_node.h>
16 #include <vppinfra/hash.h>
17 #include <vnet/unix/pcap.h>
18 #include <vnet/srp/srp.h>
19 #include <vnet/ppp/ppp.h>
20 #include <vnet/hdlc/hdlc.h>
21 #include <vnet/srp/packet.h>
22 
23 /*
24  * Generate a set of specific CDP TLVs.
25  *
26  * $$$ eventually these need to fish better data from
27  * other data structures; e.g. the hostname, software version info
28  * etc.
29  */
30 
31 static void
33 {
34  cdp_tlv_t *t = (cdp_tlv_t *) * t0p;
35 
36  t->t = htons (CDP_TLV_device_name);
37  t->l = htons (3 + sizeof (*t));
38  clib_memcpy (&t->v, "VPP", 3);
39 
40  *t0p += ntohs (t->l);
41 }
42 
43 static void
45 {
46  cdp_tlv_t *t = (cdp_tlv_t *) * t0p;
47 
48  t->t = htons (CDP_TLV_port_id);
49  t->l = htons (vec_len (hw->name) + sizeof (*t));
50  clib_memcpy (&t->v, hw->name, vec_len (hw->name));
51  *t0p += ntohs (t->l);
52 }
53 
54 static void
56 {
57  cdp_tlv_t *t = (cdp_tlv_t *) * t0p;
58 
59  t->t = htons (CDP_TLV_version);
60  t->l = htons (12 + sizeof (*t));
61  clib_memcpy (&t->v, "VPP Software", 12);
62  *t0p += ntohs (t->l);
63 }
64 
65 static void
67 {
68  cdp_tlv_t *t = (cdp_tlv_t *) * t0p;
69 
70  t->t = htons (CDP_TLV_platform);
71  t->l = htons (2 + sizeof (*t));
72  clib_memcpy (&t->v, "SW", 2);
73  *t0p += ntohs (t->l);
74 }
75 
76 static void
78 {
79  cdp_tlv_t *t = (cdp_tlv_t *) * t0p;
80  u32 capabilities;
81 
82  t->t = htons (CDP_TLV_capabilities);
83  t->l = htons (4 + sizeof (*t));
84  capabilities = CDP_ROUTER_DEVICE;
85  capabilities = htonl (capabilities);
86  clib_memcpy (&t->v, &capabilities, sizeof (capabilities));
87  *t0p += ntohs (t->l);
88 }
89 
90 static void
92 {
93  add_device_name_tlv (hw, t0p);
94  add_port_id_tlv (hw, t0p);
95  add_version_tlv (hw, t0p);
96  add_platform_tlv (hw, t0p);
97  add_capability_tlv (hw, t0p);
98 }
99 
100 /*
101  * send a cdp pkt on an ethernet interface
102  */
103 static void
105 {
106  u32 *to_next;
107  ethernet_llc_snap_and_cdp_header_t *h0;
109  u32 bi0;
110  vlib_buffer_t *b0;
111  u8 *t0;
112  u16 checksum;
113  int nbytes_to_checksum;
114  int i;
115  vlib_frame_t *f;
116  vlib_main_t *vm = cm->vlib_main;
117  vnet_main_t *vnm = cm->vnet_main;
118 
119  for (i = 0; i < count; i++)
120  {
121  /*
122  * see cdp_periodic_init() to understand what's already painted
123  * into the buffer by the packet template mechanism
124  */
126  (vm, &cm->packet_templates[n->packet_template_index], &bi0);
127 
128  /* Add the interface's ethernet source address */
129  hw = vnet_get_sup_hw_interface (vnm, n->sw_if_index);
130 
131  clib_memcpy (h0->ethernet.src_address, hw->hw_address,
132  vec_len (hw->hw_address));
133 
134  t0 = (u8 *) & h0->cdp.data;
135 
136  /* add TLVs */
137  add_tlvs (cm, hw, &t0);
138 
139  /* add the cdp packet checksum */
140  nbytes_to_checksum = t0 - (u8 *) & h0->cdp;
141  checksum = cdp_checksum (&h0->cdp, nbytes_to_checksum);
142  h0->cdp.checksum = htons (checksum);
143 
144  /* Set the outbound packet length */
145  b0 = vlib_get_buffer (vm, bi0);
146  b0->current_length = nbytes_to_checksum + sizeof (*h0)
147  - sizeof (cdp_hdr_t);
148 
149  /* And the outbound interface */
150  vnet_buffer (b0)->sw_if_index[VLIB_TX] = hw->sw_if_index;
151 
152  /* Set the 802.3 ethernet length */
153  h0->ethernet.len = htons (b0->current_length
154  - sizeof (ethernet_802_3_header_t));
155 
156  /* And output the packet on the correct interface */
158  to_next = vlib_frame_vector_args (f);
159  to_next[0] = bi0;
160  f->n_vectors = 1;
161 
163  n->last_sent = vlib_time_now (vm);
164  }
165 }
166 
167 /*
168  * send a cdp pkt on an hdlc interface
169  */
170 static void
172 {
173  u32 *to_next;
174  hdlc_and_cdp_header_t *h0;
176  u32 bi0;
177  vlib_buffer_t *b0;
178  u8 *t0;
179  u16 checksum;
180  int nbytes_to_checksum;
181  int i;
182  vlib_frame_t *f;
183  vlib_main_t *vm = cm->vlib_main;
184  vnet_main_t *vnm = cm->vnet_main;
185 
186  for (i = 0; i < count; i++)
187  {
188  /*
189  * see cdp_periodic_init() to understand what's already painted
190  * into the buffer by the packet template mechanism
191  */
193  (vm, &cm->packet_templates[n->packet_template_index], &bi0);
194 
195  hw = vnet_get_sup_hw_interface (vnm, n->sw_if_index);
196 
197  t0 = (u8 *) & h0->cdp.data;
198 
199  /* add TLVs */
200  add_tlvs (cm, hw, &t0);
201 
202  /* add the cdp packet checksum */
203  nbytes_to_checksum = t0 - (u8 *) & h0->cdp;
204  checksum = cdp_checksum (&h0->cdp, nbytes_to_checksum);
205  h0->cdp.checksum = htons (checksum);
206 
207  /* Set the outbound packet length */
208  b0 = vlib_get_buffer (vm, bi0);
209  b0->current_length = nbytes_to_checksum + sizeof (*h0)
210  - sizeof (cdp_hdr_t);
211 
212  /* And output the packet on the correct interface */
214  to_next = vlib_frame_vector_args (f);
215  to_next[0] = bi0;
216  f->n_vectors = 1;
217 
219  n->last_sent = vlib_time_now (vm);
220  }
221 }
222 
223 /*
224  * send a cdp pkt on an srp interface
225  */
226 static void
228 {
229  u32 *to_next;
230  srp_and_cdp_header_t *h0;
232  u32 bi0;
233  vlib_buffer_t *b0;
234  u8 *t0;
235  u16 checksum;
236  int nbytes_to_checksum;
237  int i;
238  vlib_frame_t *f;
239  vlib_main_t *vm = cm->vlib_main;
240  vnet_main_t *vnm = cm->vnet_main;
241 
242  for (i = 0; i < count; i++)
243  {
244  /*
245  * see cdp_periodic_init() to understand what's already painted
246  * into the buffer by the packet template mechanism
247  */
249  (vm, &cm->packet_templates[n->packet_template_index], &bi0);
250 
251  hw = vnet_get_sup_hw_interface (vnm, n->sw_if_index);
252 
253  t0 = (u8 *) & h0->cdp.data;
254 
255  /* add TLVs */
256  add_tlvs (cm, hw, &t0);
257 
258  /* Add the interface's ethernet source address */
259  clib_memcpy (h0->ethernet.src_address, hw->hw_address,
260  vec_len (hw->hw_address));
261 
262  /* add the cdp packet checksum */
263  nbytes_to_checksum = t0 - (u8 *) & h0->cdp;
264  checksum = cdp_checksum (&h0->cdp, nbytes_to_checksum);
265  h0->cdp.checksum = htons (checksum);
266 
267  /* Set the outbound packet length */
268  b0 = vlib_get_buffer (vm, bi0);
269  b0->current_length = nbytes_to_checksum + sizeof (*h0)
270  - sizeof (cdp_hdr_t);
271 
272  /* And output the packet on the correct interface */
274  to_next = vlib_frame_vector_args (f);
275  to_next[0] = bi0;
276  f->n_vectors = 1;
277 
279  n->last_sent = vlib_time_now (vm);
280  }
281 }
282 
283 /*
284  * Decide which cdp packet template to use
285  */
286 static int
288 {
290 
291  return 0;
292 }
293 
294 /* Send a cdp neighbor announcement */
295 static void
296 send_hello (cdp_main_t * cm, cdp_neighbor_t * n, int count)
297 {
298  if (n->packet_template_index == (u8) ~ 0)
299  {
300  /* If we don't know how to talk to this peer, don't try again */
301  if (pick_packet_template (cm, n))
302  {
303  n->last_sent = 1e70;
304  return;
305  }
306  }
307 
308  switch (n->packet_template_index)
309  {
311  send_ethernet_hello (cm, n, count);
312  break;
313 
315  send_hdlc_hello (cm, n, count);
316  break;
317 
319  send_srp_hello (cm, n, count);
320  break;
321 
322  default:
323  ASSERT (0);
324  }
325  n->last_sent = vlib_time_now (cm->vlib_main);
326 }
327 
328 static void
329 delete_neighbor (cdp_main_t * cm, cdp_neighbor_t * n, int want_broadcast)
330 {
332  vec_free (n->device_name);
333  vec_free (n->version);
334  vec_free (n->port_id);
335  vec_free (n->platform);
336  vec_free (n->last_rx_pkt);
337  pool_put (cm->neighbors, n);
338 }
339 
340 void
342 {
343  cdp_main_t *cm = &cdp_main;
344  cdp_neighbor_t *n;
345  f64 now = vlib_time_now (vm);
347  static u32 *delete_list = 0;
348  int i;
349  static cdp_neighbor_t **n_list = 0;
350 
351  /* *INDENT-OFF* */
352  pool_foreach (n, cm->neighbors,
353  ({
354  vec_add1 (n_list, n);
355  }));
356  /* *INDENT-ON* */
357 
358  /* Across all cdp neighbors known to the system */
359  for (i = 0; i < vec_len (n_list); i++)
360  {
361  n = n_list[i];
362 
363  /* "no cdp run" provisioned on the interface? */
364  if (n->disabled == 1)
365  continue;
366 
368 
369  /* Interface shutdown or rx timeout? */
371  || (now > (n->last_heard + (f64) n->ttl_in_seconds)))
372  /* add to list of neighbors to delete */
373  vec_add1 (delete_list, n - cm->neighbors);
374  else if (n->last_sent == 0.0)
375  /* First time, send 3 hellos */
376  send_hello (cm, n, 3 /* three to begin with */ );
377  else if (now > (n->last_sent + (((f64) n->ttl_in_seconds) / 6.0)))
378  /* Normal keepalive, send one */
379  send_hello (cm, n, 1 /* one as a keepalive */ );
380  }
381 
382  for (i = 0; i < vec_len (delete_list); i++)
383  {
384  n = vec_elt_at_index (cm->neighbors, delete_list[i]);
385  delete_neighbor (cm, n, 1);
386  }
387  if (delete_list)
388  _vec_len (delete_list) = 0;
389  if (n_list)
390  _vec_len (n_list) = 0;
391 }
392 
393 static clib_error_t *
395 {
396  cdp_main_t *cm = &cdp_main;
397 
398  /* Create the ethernet cdp hello packet template */
399  {
400  ethernet_llc_snap_and_cdp_header_t h;
401 
402  memset (&h, 0, sizeof (h));
403 
404  /* Send to 01:00:0c:cc:cc */
405  h.ethernet.dst_address[0] = 0x01;
406  /* h.ethernet.dst_address[1] = 0x00; (memset) */
407  h.ethernet.dst_address[2] = 0x0C;
408  h.ethernet.dst_address[3] = 0xCC;
409  h.ethernet.dst_address[4] = 0xCC;
410  h.ethernet.dst_address[5] = 0xCC;
411 
412  /* leave src address blank (fill in at send time) */
413 
414  /* leave length blank (fill in at send time) */
415 
416  /* LLC */
417  h.llc.dst_sap = h.llc.src_sap = 0xAA; /* SNAP */
418  h.llc.control = 0x03; /* UI (no extended control bytes) */
419 
420  /* SNAP */
421  /* h.snap.oui[0] = 0x00; (memset) */
422  /* h.snap.oui[1] = 0x00; (memset) */
423  h.snap.oui[2] = 0x0C; /* Cisco = 0x00000C */
424  h.snap.protocol = htons (0x2000); /* CDP = 0x2000 */
425 
426  /* CDP */
427  h.cdp.version = 2;
428  h.cdp.ttl = 180;
429 
432  /* data */ &h,
433  sizeof (h),
434  /* alloc chunk size */ 8,
435  "cdp-ethernet");
436  }
437 
438 #if 0 /* retain for reference */
439 
440  /* Create the hdlc cdp hello packet template */
441  {
442  hdlc_and_cdp_header_t h;
443 
444  memset (&h, 0, sizeof (h));
445 
446  h.hdlc.address = 0x0f;
447  /* h.hdlc.control = 0; (memset) */
448  h.hdlc.protocol = htons (0x2000); /* CDP = 0x2000 */
449 
450  /* CDP */
451  h.cdp.version = 2;
452  h.cdp.ttl = 180;
453 
456  /* data */ &h,
457  sizeof (h),
458  /* alloc chunk size */ 8,
459  "cdp-hdlc");
460  }
461 
462  /* Create the srp cdp hello packet template */
463  {
464  srp_and_cdp_header_t h;
465 
466  memset (&h, 0, sizeof (h));
467 
468  /* Send to 01:00:0c:cc:cc */
469  h.ethernet.dst_address[0] = 0x01;
470  /* h.ethernet.dst_address[1] = 0x00; (memset) */
471  h.ethernet.dst_address[2] = 0x0C;
472  h.ethernet.dst_address[3] = 0xCC;
473  h.ethernet.dst_address[4] = 0xCC;
474  h.ethernet.dst_address[5] = 0xCC;
475 
476  /* leave src address blank (fill in at send time) */
477 
478  /* The srp header is filled in at xmt */
479  h.srp.ttl = 1;
480  h.srp.priority = 7;
481  h.srp.mode = SRP_MODE_data;
482  srp_header_compute_parity (&h.srp);
483 
484  /* Inner ring and parity will be set at send time */
485 
486  h.ethernet.type = htons (0x2000); /* CDP = 0x2000 */
487 
488  /* CDP */
489  h.cdp.version = 2;
490  h.cdp.ttl = 180;
491 
494  /* data */ &h,
495  sizeof (h),
496  /* alloc chunk size */ 8,
497  "cdp-srp");
498  }
499 #endif
500 
501  return 0;
502 }
503 
505 
506 /*
507  * fd.io coding-style-patch-verification: ON
508  *
509  * Local Variables:
510  * eval: (c-set-style "gnu")
511  * End:
512  */
static void add_capability_tlv(vnet_hw_interface_t *hw, u8 **t0p)
Definition: cdp_periodic.c:77
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
void cdp_periodic(vlib_main_t *vm)
Definition: cdp_periodic.c:341
#define hash_unset(h, key)
Definition: hash.h:260
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
static void delete_neighbor(cdp_main_t *cm, cdp_neighbor_t *n, int want_broadcast)
Definition: cdp_periodic.c:329
u16 cdp_checksum(void *p, int count)
Definition: cdp_input.c:30
PCAP utility definitions.
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:182
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
static void add_tlvs(cdp_main_t *cm, vnet_hw_interface_t *hw, u8 **t0p)
Definition: cdp_periodic.c:91
u8 * version
Definition: cdp_node.h:62
static vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
static void srp_header_compute_parity(srp_header_t *h)
Definition: packet.h:89
u8 packet_template_index
Definition: cdp_node.h:54
static void send_ethernet_hello(cdp_main_t *cm, cdp_neighbor_t *n, int count)
Definition: cdp_periodic.c:104
cdp_main_t cdp_main
Definition: cdp_input.c:17
uword * neighbor_by_sw_if_index
Definition: cdp_node.h:85
void vlib_packet_template_init(vlib_main_t *vm, vlib_packet_template_t *t, void *packet_data, uword n_packet_data_bytes, uword min_n_buffers_each_physmem_alloc, char *fmt,...)
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:348
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
static void add_port_id_tlv(vnet_hw_interface_t *hw, u8 **t0p)
Definition: cdp_periodic.c:44
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
static void add_version_tlv(vnet_hw_interface_t *hw, u8 **t0p)
Definition: cdp_periodic.c:55
vnet_main_t * vnet_main
Definition: cdp_node.h:95
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:82
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:214
f64 last_heard
Definition: cdp_node.h:44
cdp_neighbor_t * neighbors
Definition: cdp_node.h:79
static void send_hello(cdp_main_t *cm, cdp_neighbor_t *n, int count)
Definition: cdp_periodic.c:296
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:196
static void send_hdlc_hello(cdp_main_t *cm, cdp_neighbor_t *n, int count)
Definition: cdp_periodic.c:171
u16 n_vectors
Definition: node.h:344
#define CDP_ROUTER_DEVICE
Definition: cdp_protocol.h:148
static void send_srp_hello(cdp_main_t *cm, cdp_neighbor_t *n, int count)
Definition: cdp_periodic.c:227
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
u8 * last_rx_pkt
Definition: cdp_node.h:67
u8 * device_name
Definition: cdp_node.h:61
#define clib_memcpy(a, b, c)
Definition: string.h:69
static clib_error_t * cdp_periodic_init(vlib_main_t *vm)
Definition: cdp_periodic.c:394
u8 ttl_in_seconds
Definition: cdp_node.h:48
#define VNET_SW_INTERFACE_FLAG_ADMIN_UP
Definition: interface.h:528
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
#define vnet_buffer(b)
Definition: buffer.h:361
vlib_main_t * vlib_main
Definition: cdp_node.h:94
vlib_packet_template_t packet_templates[CDP_N_PACKET_TEMPLATES]
Definition: cdp_node.h:91
static void add_device_name_tlv(vnet_hw_interface_t *hw, u8 **t0p)
Definition: cdp_periodic.c:32
Definition: defs.h:47
unsigned short u16
Definition: types.h:57
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
u8 * port_id
Definition: cdp_node.h:63
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:253
static int pick_packet_template(cdp_main_t *cm, cdp_neighbor_t *n)
Definition: cdp_periodic.c:287
void * vlib_packet_template_get_packet(vlib_main_t *vm, vlib_packet_template_t *t, u32 *bi_result)
u8 * platform
Definition: cdp_node.h:64
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:187
static void add_platform_tlv(vnet_hw_interface_t *hw, u8 **t0p)
Definition: cdp_periodic.c:66
u32 sw_if_index
Definition: cdp_node.h:41
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57