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