Trivial: Clean up some typos.
[vpp.git] / src / vnet / lldp / lldp_output.c
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 (&(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 ((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
46 lldp_add_chassis_id (const vnet_hw_interface_t * hw, u8 ** t0p)
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 (&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
62 lldp_add_port_id (const vnet_hw_interface_t * hw, u8 ** t0p)
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 (&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 (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 (t->v, lm->sys_name, len);
125       *t0p += STRUCT_SIZE_OF (lldp_tlv_t, head) + len;
126     }
127 }
128
129 static void
130 lldp_add_mgmt_addr (const lldp_intf_t * n, const vnet_hw_interface_t * hw,
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
174 lldp_add_pdu_end (u8 ** t0p)
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
183 lldp_add_tlvs (lldp_main_t * lm, vnet_hw_interface_t * hw, u8 ** t0p,
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;
203   vnet_hw_interface_t *hw;
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
223   clib_memcpy (h0->src_address, hw->hw_address, vec_len (hw->hw_address));
224
225   u8 *data = ((u8 *) h0) + sizeof (*h0);
226   t0 = data;
227
228   /* add TLVs */
229   lldp_add_tlvs (lm, hw, &t0, shutdown, n);
230
231   /* Set the outbound packet length */
232   b0 = vlib_get_buffer (vm, bi0);
233   b0->current_length = sizeof (*h0) + t0 - data;
234
235   /* And the outbound interface */
236   vnet_buffer (b0)->sw_if_index[VLIB_TX] = hw->sw_if_index;
237
238   /* And output the packet on the correct interface */
239   f = vlib_get_frame_to_node (vm, hw->output_node_index);
240   to_next = vlib_frame_vector_args (f);
241   to_next[0] = bi0;
242   f->n_vectors = 1;
243
244   vlib_put_frame_to_node (vm, hw->output_node_index, f);
245   n->last_sent = vlib_time_now (vm);
246 }
247
248 void
249 lldp_delete_intf (lldp_main_t * lm, lldp_intf_t * n)
250 {
251   if (n)
252     {
253       lldp_unschedule_intf (lm, n);
254       hash_unset (lm->intf_by_hw_if_index, n->hw_if_index);
255       vec_free (n->chassis_id);
256       vec_free (n->port_id);
257       vec_free (n->port_desc);
258       vec_free (n->mgmt_ip4);
259       vec_free (n->mgmt_ip6);
260       vec_free (n->mgmt_oid);
261       pool_put (lm->intfs, n);
262     }
263 }
264
265 static clib_error_t *
266 lldp_template_init (vlib_main_t * vm)
267 {
268   lldp_main_t *lm = &lldp_main;
269
270   /* Create the ethernet lldp packet template */
271   {
272     ethernet_header_t h;
273
274     memset (&h, 0, sizeof (h));
275
276     /*
277      * Send to 01:80:C2:00:00:0E - propagation constrained to a single
278      * physical link - stopped by all type of bridge
279      */
280     h.dst_address[0] = 0x01;
281     h.dst_address[1] = 0x80;
282     h.dst_address[2] = 0xC2;
283     /* h.dst_address[3] = 0x00; (memset) */
284     /* h.dst_address[4] = 0x00; (memset) */
285     h.dst_address[5] = 0x0E;
286
287     /* leave src address blank (fill in at send time) */
288
289     h.type = htons (ETHERNET_TYPE_802_1_LLDP);
290
291     vlib_packet_template_init (vm, &lm->packet_template,
292                                /* data */ &h, sizeof (h),
293                                /* alloc chunk size */ 8, "lldp-ethernet");
294   }
295
296   return 0;
297 }
298
299 VLIB_INIT_FUNCTION (lldp_template_init);
300
301 /*
302  * fd.io coding-style-patch-verification: ON
303  *
304  * Local Variables:
305  * eval: (c-set-style "gnu")
306  * End:
307  */