FD.io VPP  v19.01.3-6-g70449b9b9
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
22 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  lldp_tlv_t *t = (lldp_tlv_t *) * t0p;
26 
27  lldp_tlv_set_code (t, LLDP_TLV_NAME (mgmt_addr));
28  t->v[0] = addr_len + 1; /* address string length */
29  t->v[1] = subtype; /* address subtype */
30  clib_memcpy_fast (&(t->v[2]), addr, addr_len); /* address */
31  t->v[addr_len + 2] = 2; /* interface numbering subtype: ifIndex */
32  t->v[addr_len + 3] = (if_index >> 24) & 0xFF; /* interface number */
33  t->v[addr_len + 4] = (if_index >> 16) & 0xFF;
34  t->v[addr_len + 5] = (if_index >> 8) & 0xFF;
35  t->v[addr_len + 6] = (if_index >> 0) & 0xFF;
36  t->v[addr_len + 7] = oid_len; /* OID string length */
37 
38  if (oid_len > 0)
39  clib_memcpy_fast ((u8 *) & (t->v[addr_len + 8]), oid, oid_len);
40 
41  lldp_tlv_set_length (t, addr_len + oid_len + 8);
42  *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + addr_len + oid_len + 8;
43 }
44 
45 static void
47 {
48  lldp_chassis_id_tlv_t *t = (lldp_chassis_id_tlv_t *) * t0p;
49 
50  lldp_tlv_set_code ((lldp_tlv_t *) t, LLDP_TLV_NAME (chassis_id));
51  t->subtype = LLDP_CHASS_ID_SUBTYPE_NAME (mac_addr);
52 
53  const size_t addr_len = 6;
54  clib_memcpy_fast (&t->id, hw->hw_address, addr_len);
55  const size_t len =
56  STRUCT_SIZE_OF (lldp_chassis_id_tlv_t, subtype) + addr_len;
57  lldp_tlv_set_length ((lldp_tlv_t *) t, len);
58  *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + len;
59 }
60 
61 static void
63 {
64  lldp_port_id_tlv_t *t = (lldp_port_id_tlv_t *) * t0p;
65 
66  lldp_tlv_set_code ((lldp_tlv_t *) t, LLDP_TLV_NAME (port_id));
67  t->subtype = LLDP_PORT_ID_SUBTYPE_NAME (intf_name);
68 
69  const size_t name_len = vec_len (hw->name);
70  clib_memcpy_fast (&t->id, hw->name, name_len);
71  const size_t len = STRUCT_SIZE_OF (lldp_port_id_tlv_t, subtype) + name_len;
72  lldp_tlv_set_length ((lldp_tlv_t *) t, len);
73  *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + len;
74 }
75 
76 static void
77 lldp_add_ttl (const lldp_main_t * lm, u8 ** t0p, int shutdown)
78 {
79  lldp_ttl_tlv_t *t = (lldp_ttl_tlv_t *) * t0p;
80  lldp_tlv_set_code ((lldp_tlv_t *) t, LLDP_TLV_NAME (ttl));
81  if (shutdown)
82  {
83  t->ttl = 0;
84  }
85  else
86  {
87  if ((size_t) lm->msg_tx_interval * lm->msg_tx_hold + 1 > (1 << 16) - 1)
88  {
89  t->ttl = htons ((1 << 16) - 1);
90  }
91  else
92  {
93  t->ttl = htons (lm->msg_tx_hold * lm->msg_tx_interval + 1);
94  }
95  }
96  const size_t len = STRUCT_SIZE_OF (lldp_ttl_tlv_t, ttl);
97  lldp_tlv_set_length ((lldp_tlv_t *) t, len);
98  *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + len;
99 }
100 
101 static void
102 lldp_add_port_desc (const lldp_main_t * lm, lldp_intf_t * n, u8 ** t0p)
103 {
104  const size_t len = vec_len (n->port_desc);
105  if (len)
106  {
107  lldp_tlv_t *t = (lldp_tlv_t *) * t0p;
108  lldp_tlv_set_code (t, LLDP_TLV_NAME (port_desc));
109  lldp_tlv_set_length (t, len);
110  clib_memcpy_fast (t->v, n->port_desc, len);
111  *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + len;
112  }
113 }
114 
115 static void
116 lldp_add_sys_name (const lldp_main_t * lm, u8 ** t0p)
117 {
118  const size_t len = vec_len (lm->sys_name);
119  if (len)
120  {
121  lldp_tlv_t *t = (lldp_tlv_t *) * t0p;
122  lldp_tlv_set_code (t, LLDP_TLV_NAME (sys_name));
123  lldp_tlv_set_length (t, len);
124  clib_memcpy_fast (t->v, lm->sys_name, len);
125  *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + len;
126  }
127 }
128 
129 static void
131  u8 ** t0p)
132 {
133  const size_t len_ip4 = vec_len (n->mgmt_ip4);
134  const size_t len_ip6 = vec_len (n->mgmt_ip6);
135 
136  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  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  vec_len (n->mgmt_oid), /* OID length */
148  n->mgmt_oid); /* OID */
149  return;
150  }
151 
152  if (len_ip4)
153  {
154  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  vec_len (n->mgmt_oid), /* OID length */
159  n->mgmt_oid); /* OID */
160  }
161 
162  if (len_ip6)
163  {
164  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  vec_len (n->mgmt_oid), /* OID length */
169  n->mgmt_oid); /* OID */
170  }
171 }
172 
173 static void
175 {
176  lldp_tlv_t *t = (lldp_tlv_t *) * t0p;
177  lldp_tlv_set_code (t, LLDP_TLV_NAME (pdu_end));
178  lldp_tlv_set_length (t, 0);
179  *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head);
180 }
181 
182 static void
184  int shutdown, lldp_intf_t * n)
185 {
186  lldp_add_chassis_id (hw, t0p);
187  lldp_add_port_id (hw, t0p);
188  lldp_add_ttl (lm, t0p, shutdown);
189  lldp_add_port_desc (lm, n, t0p);
190  lldp_add_sys_name (lm, t0p);
191  lldp_add_mgmt_addr (n, hw, t0p);
192  lldp_add_pdu_end (t0p);
193 }
194 
195 /*
196  * send a lldp pkt on an ethernet interface
197  */
198 void
199 lldp_send_ethernet (lldp_main_t * lm, lldp_intf_t * n, int shutdown)
200 {
201  u32 *to_next;
202  ethernet_header_t *h0;
204  u32 bi0;
205  vlib_buffer_t *b0;
206  u8 *t0;
207  vlib_frame_t *f;
208  vlib_main_t *vm = lm->vlib_main;
209  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  h0 = vlib_packet_template_get_packet (vm, &lm->packet_template, &bi0);
216 
217  if (!h0)
218  return;
219 
220  /* Add the interface's ethernet source address */
221  hw = vnet_get_hw_interface (vnm, n->hw_if_index);
222 
224  vec_len (hw->hw_address));
225 
226  u8 *data = ((u8 *) h0) + sizeof (*h0);
227  t0 = data;
228 
229  /* add TLVs */
230  lldp_add_tlvs (lm, hw, &t0, shutdown, n);
231 
232  /* Set the outbound packet length */
233  b0 = vlib_get_buffer (vm, bi0);
234  b0->current_length = sizeof (*h0) + t0 - data;
235 
236  /* And the outbound interface */
237  vnet_buffer (b0)->sw_if_index[VLIB_TX] = hw->sw_if_index;
238 
239  /* And output the packet on the correct interface */
241  to_next = vlib_frame_vector_args (f);
242  to_next[0] = bi0;
243  f->n_vectors = 1;
244 
246  n->last_sent = vlib_time_now (vm);
247 }
248 
249 void
251 {
252  if (n)
253  {
254  lldp_unschedule_intf (lm, n);
256  vec_free (n->chassis_id);
257  vec_free (n->port_id);
258  vec_free (n->port_desc);
259  vec_free (n->mgmt_ip4);
260  vec_free (n->mgmt_ip6);
261  vec_free (n->mgmt_oid);
262  pool_put (lm->intfs, n);
263  }
264 }
265 
266 static clib_error_t *
268 {
269  lldp_main_t *lm = &lldp_main;
270 
271  /* Create the ethernet lldp packet template */
272  {
274 
275  clib_memset (&h, 0, sizeof (h));
276 
277  /*
278  * Send to 01:80:C2:00:00:0E - propagation constrained to a single
279  * physical link - stopped by all type of bridge
280  */
281  h.dst_address[0] = 0x01;
282  h.dst_address[1] = 0x80;
283  h.dst_address[2] = 0xC2;
284  /* h.dst_address[3] = 0x00; (clib_memset) */
285  /* h.dst_address[4] = 0x00; (clib_memset) */
286  h.dst_address[5] = 0x0E;
287 
288  /* leave src address blank (fill in at send time) */
289 
290  h.type = htons (ETHERNET_TYPE_802_1_LLDP);
291 
293  /* data */ &h, sizeof (h),
294  /* alloc chunk size */ 8, "lldp-ethernet");
295  }
296 
297  return 0;
298 }
299 
301 
302 /*
303  * fd.io coding-style-patch-verification: ON
304  *
305  * Local Variables:
306  * eval: (c-set-style "gnu")
307  * End:
308  */
lldp_main_t lldp_main
Definition: lldp_input.c:117
vnet_main_t * vnet_main
Definition: lldp_node.h:81
u8 * mgmt_ip4
Definition: lldp_node.h:50
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:261
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
u8 * chassis_id
Definition: lldp_node.h:40
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
lldp_intf_t * intfs
Definition: lldp_node.h:62
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:232
u8 src_address[6]
Definition: packet.h:56
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
vhost_vring_addr_t addr
Definition: vhost_user.h:121
unsigned char u8
Definition: types.h:56
static void lldp_add_mgmt_addr(const lldp_intf_t *n, const vnet_hw_interface_t *hw, u8 **t0p)
Definition: lldp_output.c:130
u8 msg_tx_hold
Definition: lldp_node.h:93
void * vlib_packet_template_get_packet(vlib_main_t *vm, vlib_packet_template_t *t, u32 *bi_result)
Definition: buffer.c:688
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:163
u8 * port_id
Definition: lldp_node.h:41
u8 dst_address[6]
Definition: packet.h:55
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:77
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:181
unsigned int u32
Definition: types.h:88
void lldp_send_ethernet(lldp_main_t *lm, lldp_intf_t *n, int shutdown)
Definition: lldp_output.c:199
static void lldp_add_sys_name(const lldp_main_t *lm, u8 **t0p)
Definition: lldp_output.c:116
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_alloc, char *fmt,...)
Definition: buffer.c:665
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:114
u16 msg_tx_interval
Definition: lldp_node.h:102
uword * intf_by_hw_if_index
Definition: lldp_node.h:65
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:190
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:286
static void lldp_add_chassis_id(const vnet_hw_interface_t *hw, u8 **t0p)
Definition: lldp_output.c:46
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:250
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:183
u8 len
Definition: ip_types.api:49
u16 n_vectors
Definition: node.h:420
vlib_main_t * vm
Definition: buffer.c:301
u8 * port_desc
Definition: lldp_node.h:47
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
static void lldp_build_mgmt_addr_tlv(u8 **t0p, u8 subtype, u8 addr_len, u8 *addr, u32 if_index, u8 oid_len, u8 *oid)
Definition: lldp_output.c:22
u8 * mgmt_oid
Definition: lldp_node.h:56
static void lldp_add_port_desc(const lldp_main_t *lm, lldp_intf_t *n, u8 **t0p)
Definition: lldp_output.c:102
u8 * mgmt_ip6
Definition: lldp_node.h:53
static void lldp_add_pdu_end(u8 **t0p)
Definition: lldp_output.c:174
vlib_main_t * vlib_main
Definition: lldp_node.h:80
Definition: defs.h:47
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
void lldp_unschedule_intf(lldp_main_t *lm, lldp_intf_t *n)
Definition: lldp_node.c:267
#define vnet_buffer(b)
Definition: buffer.h:368
LLDP global declarations.
#define STRUCT_SIZE_OF(t, f)
Definition: clib.h:67
vlib_packet_template_t packet_template
Definition: lldp_node.h:77
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:62
u8 * sys_name
Definition: lldp_node.h:84
static clib_error_t * lldp_template_init(vlib_main_t *vm)
Definition: lldp_output.c:267
static void lldp_add_port_id(const vnet_hw_interface_t *hw, u8 **t0p)
Definition: lldp_output.c:62
#define LLDP_TLV_NAME(t)
Definition: lldp_protocol.h:44