FD.io VPP  v17.10-9-gd594711
Vector Packet Processing
lldp_output.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 generation implementation
18  */
19 #include <vnet/lldp/lldp_node.h>
20 
21 static void
23 {
24  lldp_chassis_id_tlv_t *t = (lldp_chassis_id_tlv_t *) * t0p;
25 
26  lldp_tlv_set_code ((lldp_tlv_t *) t, LLDP_TLV_NAME (chassis_id));
27  t->subtype = LLDP_CHASS_ID_SUBTYPE_NAME (mac_addr);
28 
29  const size_t addr_len = 6;
30  clib_memcpy (&t->id, hw->hw_address, addr_len);
31  const size_t len =
32  STRUCT_SIZE_OF (lldp_chassis_id_tlv_t, subtype) + addr_len;
33  lldp_tlv_set_length ((lldp_tlv_t *) t, len);
34  *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + len;
35 }
36 
37 static void
39 {
40  lldp_port_id_tlv_t *t = (lldp_port_id_tlv_t *) * t0p;
41 
42  lldp_tlv_set_code ((lldp_tlv_t *) t, LLDP_TLV_NAME (port_id));
43  t->subtype = LLDP_PORT_ID_SUBTYPE_NAME (intf_name);
44 
45  const size_t name_len = vec_len (hw->name);
46  clib_memcpy (&t->id, hw->name, name_len);
47  const size_t len = STRUCT_SIZE_OF (lldp_port_id_tlv_t, subtype) + name_len;
48  lldp_tlv_set_length ((lldp_tlv_t *) t, len);
49  *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + len;
50 }
51 
52 static void
53 lldp_add_ttl (const lldp_main_t * lm, u8 ** t0p, int shutdown)
54 {
55  lldp_ttl_tlv_t *t = (lldp_ttl_tlv_t *) * t0p;
56  lldp_tlv_set_code ((lldp_tlv_t *) t, LLDP_TLV_NAME (ttl));
57  if (shutdown)
58  {
59  t->ttl = 0;
60  }
61  else
62  {
63  if ((size_t) lm->msg_tx_interval * lm->msg_tx_hold + 1 > (1 << 16) - 1)
64  {
65  t->ttl = htons ((1 << 16) - 1);
66  }
67  else
68  {
69  t->ttl = htons (lm->msg_tx_hold * lm->msg_tx_interval + 1);
70  }
71  }
72  const size_t len = STRUCT_SIZE_OF (lldp_ttl_tlv_t, ttl);
73  lldp_tlv_set_length ((lldp_tlv_t *) t, len);
74  *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + len;
75 }
76 
77 static void
78 lldp_add_port_desc (const lldp_main_t * lm, lldp_intf_t * n, u8 ** t0p)
79 {
80  const size_t len = vec_len (n->port_desc);
81  if (len)
82  {
83  lldp_tlv_t *t = (lldp_tlv_t *) * t0p;
84  lldp_tlv_set_code (t, LLDP_TLV_NAME (port_desc));
85  lldp_tlv_set_length (t, len);
86  clib_memcpy (t->v, n->port_desc, len);
87  *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + len;
88  }
89 }
90 
91 static void
92 lldp_add_sys_name (const lldp_main_t * lm, u8 ** t0p)
93 {
94  const size_t len = vec_len (lm->sys_name);
95  if (len)
96  {
97  lldp_tlv_t *t = (lldp_tlv_t *) * t0p;
98  lldp_tlv_set_code (t, LLDP_TLV_NAME (sys_name));
99  lldp_tlv_set_length (t, len);
100  clib_memcpy (t->v, lm->sys_name, len);
101  *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + len;
102  }
103 }
104 
105 static void
107 {
108  lldp_tlv_t *t = (lldp_tlv_t *) * t0p;
109  lldp_tlv_set_code (t, LLDP_TLV_NAME (pdu_end));
110  lldp_tlv_set_length (t, 0);
111  *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head);
112 }
113 
114 static void
116  int shutdown, lldp_intf_t * n)
117 {
118  lldp_add_chassis_id (hw, t0p);
119  lldp_add_port_id (hw, t0p);
120  lldp_add_ttl (lm, t0p, shutdown);
121  lldp_add_port_desc (lm, n, t0p);
122  lldp_add_sys_name (lm, t0p);
123  lldp_add_pdu_end (t0p);
124 }
125 
126 /*
127  * send a lldp pkt on an ethernet interface
128  */
129 void
130 lldp_send_ethernet (lldp_main_t * lm, lldp_intf_t * n, int shutdown)
131 {
132  u32 *to_next;
133  ethernet_header_t *h0;
135  u32 bi0;
136  vlib_buffer_t *b0;
137  u8 *t0;
138  vlib_frame_t *f;
139  vlib_main_t *vm = lm->vlib_main;
140  vnet_main_t *vnm = lm->vnet_main;
141 
142  /*
143  * see lldp_template_init() to understand what's already painted
144  * into the buffer by the packet template mechanism
145  */
146  h0 = vlib_packet_template_get_packet (vm, &lm->packet_template, &bi0);
147 
148  if (!h0)
149  return;
150 
151  /* Add the interface's ethernet source address */
152  hw = vnet_get_hw_interface (vnm, n->hw_if_index);
153 
155 
156  u8 *data = ((u8 *) h0) + sizeof (*h0);
157  t0 = data;
158 
159  /* add TLVs */
160  lldp_add_tlvs (lm, hw, &t0, shutdown, n);
161 
162  /* Set the outbound packet length */
163  b0 = vlib_get_buffer (vm, bi0);
164  b0->current_length = sizeof (*h0) + t0 - data;
165 
166  /* And the outbound interface */
167  vnet_buffer (b0)->sw_if_index[VLIB_TX] = hw->sw_if_index;
168 
169  /* And output the packet on the correct interface */
171  to_next = vlib_frame_vector_args (f);
172  to_next[0] = bi0;
173  f->n_vectors = 1;
174 
176  n->last_sent = vlib_time_now (vm);
177 }
178 
179 void
181 {
182  if (n)
183  {
184  lldp_unschedule_intf (lm, n);
186  vec_free (n->chassis_id);
187  vec_free (n->port_id);
188  vec_free (n->port_desc);
189  pool_put (lm->intfs, n);
190  }
191 }
192 
193 static clib_error_t *
195 {
196  lldp_main_t *lm = &lldp_main;
197 
198  /* Create the ethernet lldp packet template */
199  {
201 
202  memset (&h, 0, sizeof (h));
203 
204  /*
205  * Send to 01:80:C2:00:00:0E - propagation constrained to a single
206  * physical link - stopped by all type of bridge
207  */
208  h.dst_address[0] = 0x01;
209  h.dst_address[1] = 0x80;
210  h.dst_address[2] = 0xC2;
211  /* h.dst_address[3] = 0x00; (memset) */
212  /* h.dst_address[4] = 0x00; (memset) */
213  h.dst_address[5] = 0x0E;
214 
215  /* leave src address blank (fill in at send time) */
216 
217  h.type = htons (ETHERNET_TYPE_802_1_LLDP);
218 
220  /* data */ &h, sizeof (h),
221  /* alloc chunk size */ 8, "lldp-ethernet");
222  }
223 
224  return 0;
225 }
226 
228 
229 /*
230  * fd.io coding-style-patch-verification: ON
231  *
232  * Local Variables:
233  * eval: (c-set-style "gnu")
234  * End:
235  */
lldp_main_t lldp_main
Definition: lldp_input.c:117
vnet_main_t * vnet_main
Definition: lldp_node.h:73
u32 hw_if_index
Definition: lldp_node.h:33
#define LLDP_CHASS_ID_SUBTYPE_NAME(t)
Definition: lldp_protocol.h:81
#define hash_unset(h, key)
Definition: hash.h:260
u8 * chassis_id
Definition: lldp_node.h:40
lldp_intf_t * intfs
Definition: lldp_node.h:54
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:221
u8 src_address[6]
Definition: packet.h:54
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
f64 last_sent
Definition: lldp_node.h:37
u8 msg_tx_hold
Definition: lldp_node.h:85
void * vlib_packet_template_get_packet(vlib_main_t *vm, vlib_packet_template_t *t, u32 *bi_result)
Definition: buffer.c:834
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
u8 * port_id
Definition: lldp_node.h:41
u8 dst_address[6]
Definition: packet.h:53
void lldp_tlv_set_code(lldp_tlv_t *tlv, lldp_tlv_code_t code)
Definition: lldp_input.c:92
static void lldp_add_ttl(const lldp_main_t *lm, u8 **t0p, int shutdown)
Definition: lldp_output.c:53
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:182
void lldp_send_ethernet(lldp_main_t *lm, lldp_intf_t *n, int shutdown)
Definition: lldp_output.c:130
static void lldp_add_sys_name(const lldp_main_t *lm, u8 **t0p)
Definition: lldp_output.c:92
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:72
u16 msg_tx_interval
Definition: lldp_node.h:94
uword * intf_by_hw_if_index
Definition: lldp_node.h:57
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:191
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:270
static void lldp_add_chassis_id(const vnet_hw_interface_t *hw, u8 **t0p)
Definition: lldp_output.c:22
void lldp_tlv_set_length(lldp_tlv_t *tlv, u16 length)
Definition: lldp_input.c:104
#define LLDP_PORT_ID_SUBTYPE_NAME(t)
void lldp_delete_intf(lldp_main_t *lm, lldp_intf_t *n)
Definition: lldp_output.c:180
static void lldp_add_tlvs(lldp_main_t *lm, vnet_hw_interface_t *hw, u8 **t0p, int shutdown, lldp_intf_t *n)
Definition: lldp_output.c:115
u16 n_vectors
Definition: node.h:344
vlib_main_t * vm
Definition: buffer.c:283
u8 * port_desc
Definition: lldp_node.h:47
vec_header_t h
Definition: buffer.c:282
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
#define clib_memcpy(a, b, c)
Definition: string.h:69
unsigned int u32
Definition: types.h:88
static void lldp_add_port_desc(const lldp_main_t *lm, lldp_intf_t *n, u8 **t0p)
Definition: lldp_output.c:78
static void lldp_add_pdu_end(u8 **t0p)
Definition: lldp_output.c:106
vlib_main_t * vlib_main
Definition: lldp_node.h:72
Definition: defs.h:47
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
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:784
void lldp_unschedule_intf(lldp_main_t *lm, lldp_intf_t *n)
Definition: lldp_node.c:267
#define vnet_buffer(b)
Definition: buffer.h:306
LLDP global declarations.
#define STRUCT_SIZE_OF(t, f)
Definition: clib.h:64
vlib_packet_template_t packet_template
Definition: lldp_node.h:69
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
u8 * sys_name
Definition: lldp_node.h:76
static clib_error_t * lldp_template_init(vlib_main_t *vm)
Definition: lldp_output.c:194
static void lldp_add_port_id(const vnet_hw_interface_t *hw, u8 **t0p)
Definition: lldp_output.c:38
#define LLDP_TLV_NAME(t)
Definition: lldp_protocol.h:44