Branch data Line data Source code
1 : : /* -*- mode: c; c-file-style: "openbsd" -*- */
2 : : /*
3 : : * Copyright (c) 2015 Nicira, Inc.
4 : : * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
5 : : *
6 : : * Permission to use, copy, modify, and/or distribute this software for any
7 : : * purpose with or without fee is hereby granted, provided that the above
8 : : * copyright notice and this permission notice appear in all copies.
9 : : *
10 : : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 : : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 : : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 : : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 : : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 : : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 : : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 : : */
18 : :
19 : : #include <config.h>
20 : : #include "lldpd.h"
21 : : #include <arpa/inet.h>
22 : : #include <errno.h>
23 : : #include <fcntl.h>
24 : : #include <inttypes.h>
25 : : #include <signal.h>
26 : : #include <stdio.h>
27 : : #include <sys/ioctl.h>
28 : : #include <sys/socket.h>
29 : : #include <sys/stat.h>
30 : : #include <sys/time.h>
31 : : #include <sys/types.h>
32 : : #include <sys/wait.h>
33 : : #include <unistd.h>
34 : : #ifndef _WIN32
35 : : #include <grp.h>
36 : : #include <libgen.h>
37 : : #include <pwd.h>
38 : : #include <sys/select.h>
39 : : #include <sys/utsname.h>
40 : : #endif
41 : : #include "compiler.h"
42 : : #include "openvswitch/list.h"
43 : : #include "packets.h"
44 : : #include "timeval.h"
45 : :
46 : 2462 : VLOG_DEFINE_THIS_MODULE(lldpd);
47 : :
48 : : static struct protocol protos[] =
49 : : {
50 : : { LLDPD_MODE_LLDP, 1, "LLDP", 'l', lldp_send, lldp_decode, NULL,
51 : : LLDP_MULTICAST_ADDR },
52 : : { 0, 0, "any", ' ', NULL, NULL, NULL,
53 : : { { { 0,0,0,0,0,0 } } } }
54 : : };
55 : :
56 : 1 : void lldpd_assign_cfg_to_protocols(struct lldpd *cfg)
57 : : {
58 : 1 : cfg->g_protocols = protos;
59 : 1 : }
60 : :
61 : : struct lldpd_hardware *
62 : 0 : lldpd_get_hardware(struct lldpd *cfg, char *name, int index,
63 : : struct lldpd_ops *ops)
64 : : {
65 : : struct lldpd_hardware *hw;
66 : :
67 [ # # ]: 0 : LIST_FOR_EACH (hw, h_entries, &cfg->g_hardware) {
68 [ # # ][ # # ]: 0 : if (!strcmp(hw->h_ifname, name) && hw->h_ifindex == index
69 [ # # ][ # # ]: 0 : && (!ops || ops == hw->h_ops)) {
70 : 0 : return hw;
71 : : }
72 : : }
73 : :
74 : 0 : return NULL;
75 : : }
76 : :
77 : : struct lldpd_hardware *
78 : 1 : lldpd_alloc_hardware(struct lldpd *cfg, char *name, int index)
79 : : {
80 : : struct lldpd_hardware *hw;
81 : :
82 [ - + ]: 1 : VLOG_DBG("allocate a new local hardware interface (%s)", name);
83 : :
84 : 1 : hw = xzalloc(sizeof *hw);
85 : 1 : hw->h_cfg = cfg;
86 : 1 : ovs_strlcpy(hw->h_ifname, name, sizeof hw->h_ifname);
87 : 1 : hw->h_ifindex = index;
88 : 1 : hw->h_lport.p_chassis = CONTAINER_OF(ovs_list_front(&cfg->g_chassis),
89 : : struct lldpd_chassis, list);
90 : 1 : hw->h_lport.p_chassis->c_refcount++;
91 : 1 : ovs_list_init(&hw->h_rports);
92 : :
93 : 1 : return hw;
94 : : }
95 : :
96 : : struct lldpd_mgmt *
97 : 0 : lldpd_alloc_mgmt(int family, void *addrptr, size_t addrsize, u_int32_t iface)
98 : : {
99 : : struct lldpd_mgmt *mgmt;
100 : :
101 [ # # ]: 0 : VLOG_DBG("allocate a new management address (family: %d)", family);
102 : :
103 [ # # ][ # # ]: 0 : if (family <= LLDPD_AF_UNSPEC || family >= LLDPD_AF_LAST) {
104 : 0 : errno = EAFNOSUPPORT;
105 : 0 : return NULL;
106 : : }
107 [ # # ]: 0 : if (addrsize > LLDPD_MGMT_MAXADDRSIZE) {
108 : 0 : errno = EOVERFLOW;
109 : 0 : return NULL;
110 : : }
111 : 0 : mgmt = xzalloc(sizeof *mgmt);
112 : 0 : mgmt->m_family = family;
113 : 0 : memcpy(&mgmt->m_addr, addrptr, addrsize);
114 : 0 : mgmt->m_addrsize = addrsize;
115 : 0 : mgmt->m_iface = iface;
116 : :
117 : 0 : return mgmt;
118 : : }
119 : :
120 : : void
121 : 0 : lldpd_hardware_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware)
122 : : {
123 [ # # ]: 0 : VLOG_DBG("cleanup hardware port %s", hardware->h_ifname);
124 : :
125 : 0 : lldpd_port_cleanup(&hardware->h_lport, true);
126 [ # # ][ # # ]: 0 : if (hardware->h_ops && hardware->h_ops->cleanup) {
127 : 0 : hardware->h_ops->cleanup(cfg, hardware);
128 : : }
129 : 0 : free(hardware);
130 : 0 : }
131 : :
132 : : void
133 : 0 : lldpd_cleanup(struct lldpd *cfg)
134 : : {
135 : : struct lldpd_hardware *hw, *hw_next;
136 : : struct lldpd_chassis *chassis, *chassis_next;
137 : :
138 [ # # ]: 0 : VLOG_DBG("cleanup all ports");
139 : :
140 [ # # ][ # # ]: 0 : LIST_FOR_EACH_SAFE (hw, hw_next, h_entries, &cfg->g_hardware) {
141 [ # # ]: 0 : if (!hw->h_flags) {
142 : 0 : ovs_list_remove(&hw->h_entries);
143 : 0 : lldpd_remote_cleanup(hw, NULL, true);
144 : 0 : lldpd_hardware_cleanup(cfg, hw);
145 : : } else {
146 : 0 : lldpd_remote_cleanup(hw, NULL, false);
147 : : }
148 : : }
149 : :
150 [ # # ]: 0 : VLOG_DBG("cleanup all chassis");
151 : :
152 [ # # ][ # # ]: 0 : LIST_FOR_EACH_SAFE (chassis, chassis_next, list, &cfg->g_chassis) {
153 [ # # ]: 0 : if (chassis->c_refcount == 0) {
154 : 0 : ovs_list_remove(&chassis->list);
155 : 0 : lldpd_chassis_cleanup(chassis, 1);
156 : : }
157 : : }
158 : 0 : }
159 : :
160 : : /* Update chassis `ochassis' with values from `chassis'. The later one is not
161 : : * expected to be part of a list! It will also be wiped from memory.
162 : : */
163 : : static void
164 : 0 : lldpd_move_chassis(struct lldpd_chassis *ochassis,
165 : : struct lldpd_chassis *chassis)
166 : : {
167 : : struct lldpd_mgmt *mgmt;
168 : 0 : int refcount = ochassis->c_refcount;
169 : 0 : int index = ochassis->c_index;
170 : : struct ovs_list listcopy;
171 : :
172 : : /* We want to keep refcount, index and list stuff from the current chassis
173 : : */
174 : 0 : memcpy(&listcopy, &ochassis->list, sizeof listcopy);
175 : 0 : lldpd_chassis_cleanup(ochassis, 0);
176 : :
177 : : /* Make the copy. */
178 : : /* WARNING: this is a kludgy hack, we need in-place copy and cannot use
179 : : * marshaling.
180 : : */
181 : 0 : memcpy(ochassis, chassis, sizeof *ochassis);
182 : 0 : ovs_list_init(&ochassis->c_mgmt);
183 : :
184 : : /* Copy of management addresses */
185 [ # # ]: 0 : LIST_FOR_EACH_POP (mgmt, m_entries, &chassis->c_mgmt) {
186 : 0 : ovs_list_insert(&ochassis->c_mgmt, &mgmt->m_entries);
187 : : }
188 : :
189 : : /* Restore saved values */
190 : 0 : ochassis->c_refcount = refcount;
191 : 0 : ochassis->c_index = index;
192 : 0 : memcpy(&ochassis->list, &listcopy, sizeof ochassis->list);
193 : :
194 : : /* Get rid of the new chassis */
195 : 0 : free(chassis);
196 : 0 : }
197 : :
198 : : static int
199 : 0 : lldpd_guess_type(struct lldpd *cfg, char *frame, int s)
200 : : {
201 : : int i;
202 : :
203 [ # # ]: 0 : if (s < ETH_ADDR_LEN) {
204 : 0 : return -1;
205 : : }
206 : :
207 [ # # ]: 0 : for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
208 [ # # ]: 0 : if (!cfg->g_protocols[i].enabled) {
209 : 0 : continue;
210 : : }
211 [ # # ]: 0 : if (cfg->g_protocols[i].guess == NULL) {
212 [ # # ]: 0 : if (memcmp(frame, &cfg->g_protocols[i].mac, ETH_ADDR_LEN) == 0) {
213 [ # # ]: 0 : VLOG_DBG("guessed protocol is %s (from MAC address)",
214 : : cfg->g_protocols[i].name);
215 : 0 : return cfg->g_protocols[i].mode;
216 : : }
217 : : } else {
218 [ # # ]: 0 : if (cfg->g_protocols[i].guess(frame, s)) {
219 [ # # ]: 0 : VLOG_DBG("guessed protocol is %s (from detector function)",
220 : : cfg->g_protocols[i].name);
221 : 0 : return cfg->g_protocols[i].mode;
222 : : }
223 : : }
224 : : }
225 : :
226 : 0 : return -1;
227 : : }
228 : :
229 : : static void
230 : 0 : lldpd_decode(struct lldpd *cfg, char *frame, int s,
231 : : struct lldpd_hardware *hw)
232 : : {
233 : : size_t listsize, i;
234 : 0 : struct lldpd_chassis *chassis, *ochassis = NULL;
235 : : struct lldpd_port *port, *oport;
236 : 0 : int guess = LLDPD_MODE_LLDP;
237 : : struct eth_header eheader;
238 : 0 : int count = 0;
239 : 0 : bool found = false;
240 : :
241 [ # # ]: 0 : VLOG_DBG("decode a received frame on %s size %d", hw->h_ifname,s);
242 : :
243 [ # # ]: 0 : if (s < sizeof(struct eth_header) + 4) {
244 : : /* Too short, just discard it */
245 : 0 : return;
246 : : }
247 : :
248 : : /* Decapsulate VLAN frames */
249 : 0 : memcpy(&eheader, frame, sizeof eheader);
250 [ # # ]: 0 : if (eheader.eth_type == htons(ETH_TYPE_VLAN)) {
251 : : /* VLAN decapsulation means to shift 4 bytes left the frame from
252 : : * offset 2 * ETH_ADDR_LEN
253 : : */
254 : 0 : memmove(frame + 2 * ETH_ADDR_LEN, frame + 2 * ETH_ADDR_LEN + 4,
255 : 0 : s - 2 * ETH_ADDR_LEN);
256 : 0 : s -= 4;
257 : : }
258 : :
259 [ # # ]: 0 : LIST_FOR_EACH (oport, p_entries, &hw->h_rports) {
260 [ # # ][ # # ]: 0 : if (oport->p_lastframe &&
261 [ # # ]: 0 : oport->p_lastframe->size == s &&
262 : 0 : !memcmp(oport->p_lastframe->frame, frame, s)) {
263 : : /* Already received the same frame */
264 [ # # ]: 0 : VLOG_DBG("duplicate frame, no need to decode");
265 : 0 : oport->p_lastupdate = time_now();
266 : 0 : return;
267 : : }
268 : : }
269 : :
270 : 0 : guess = lldpd_guess_type(cfg, frame, s);
271 [ # # ]: 0 : VLOG_DBG("guessed %d enabled:%d", guess, cfg->g_protocols[0].enabled);
272 : :
273 [ # # ]: 0 : for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
274 [ # # ]: 0 : if (!cfg->g_protocols[i].enabled) {
275 : 0 : continue;
276 : : }
277 [ # # ]: 0 : if (cfg->g_protocols[i].mode == guess) {
278 [ # # ]: 0 : VLOG_DBG("using decode function for %s protocol",
279 : : cfg->g_protocols[i].name);
280 [ # # ]: 0 : if (cfg->g_protocols[i].decode(cfg, frame, s, hw, &chassis, &port)
281 : : == -1) {
282 [ # # ]: 0 : VLOG_DBG("function for %s protocol did not "
283 : : "decode this frame",
284 : : cfg->g_protocols[i].name);
285 : 0 : return;
286 : : }
287 : 0 : chassis->c_protocol = port->p_protocol = cfg->g_protocols[i].mode;
288 : 0 : break;
289 : : }
290 [ # # ]: 0 : VLOG_DBG(" %"PRIuSIZE "mode:%d enabled:%d",
291 : : i, cfg->g_protocols[i].mode, cfg->g_protocols[i].enabled);
292 : : }
293 [ # # ]: 0 : if (cfg->g_protocols[i].mode == 0) {
294 [ # # ]: 0 : VLOG_DBG("unable to guess frame type on %s", hw->h_ifname);
295 : 0 : return;
296 : : }
297 : :
298 : : /* Do we already have the same MSAP somewhere? */
299 [ # # ]: 0 : VLOG_DBG("search for the same MSAP");
300 : :
301 [ # # ]: 0 : LIST_FOR_EACH (oport, p_entries, &hw->h_rports) {
302 [ # # ]: 0 : if (port->p_protocol == oport->p_protocol) {
303 : 0 : count++;
304 [ # # ][ # # ]: 0 : if (port->p_id_subtype == oport->p_id_subtype &&
305 [ # # ]: 0 : port->p_id_len == oport->p_id_len &&
306 [ # # ]: 0 : !memcmp(port->p_id, oport->p_id, port->p_id_len) &&
307 [ # # ]: 0 : chassis->c_id_subtype == oport->p_chassis->c_id_subtype &&
308 [ # # ]: 0 : chassis->c_id_len == oport->p_chassis->c_id_len &&
309 : 0 : !memcmp(chassis->c_id, oport->p_chassis->c_id,
310 : 0 : chassis->c_id_len)) {
311 : 0 : ochassis = oport->p_chassis;
312 [ # # ]: 0 : VLOG_DBG("MSAP is already known");
313 : 0 : found = true;
314 : 0 : break;
315 : : }
316 : : }
317 : : }
318 : :
319 [ # # ]: 0 : if (!found) {
320 : 0 : oport = NULL;
321 : : }
322 : :
323 : : /* Do we have room for a new MSAP? */
324 [ # # ][ # # ]: 0 : if (!oport && cfg->g_config.c_max_neighbors) {
325 [ # # ]: 0 : if (count == (cfg->g_config.c_max_neighbors - 1)) {
326 [ # # ]: 0 : VLOG_DBG("max neighbors %d reached for port %s, "
327 : : "dropping any new ones silently",
328 : : cfg->g_config.c_max_neighbors,
329 : : hw->h_ifname);
330 [ # # ]: 0 : } else if (count > cfg->g_config.c_max_neighbors - 1) {
331 [ # # ]: 0 : VLOG_DBG("too many neighbors for port %s, drop this new one",
332 : : hw->h_ifname);
333 : 0 : lldpd_port_cleanup(port, true);
334 : 0 : lldpd_chassis_cleanup(chassis, true);
335 : 0 : free(port);
336 : 0 : return;
337 : : }
338 : : }
339 : :
340 : : /* No, but do we already know the system? */
341 [ # # ]: 0 : if (!oport) {
342 : 0 : bool found = false;
343 [ # # ]: 0 : VLOG_DBG("MSAP is unknown, search for the chassis");
344 : :
345 [ # # ]: 0 : LIST_FOR_EACH (ochassis, list, &cfg->g_chassis) {
346 [ # # ][ # # ]: 0 : if ((chassis->c_protocol == ochassis->c_protocol) &&
347 [ # # ]: 0 : (chassis->c_id_subtype == ochassis->c_id_subtype) &&
348 [ # # ]: 0 : (chassis->c_id_len == ochassis->c_id_len) &&
349 : 0 : (memcmp(chassis->c_id, ochassis->c_id,
350 : 0 : chassis->c_id_len) == 0)) {
351 : 0 : found = true;
352 : 0 : break;
353 : : }
354 : : }
355 : :
356 [ # # ]: 0 : if (!found) {
357 : 0 : ochassis = NULL;
358 : : }
359 : : }
360 : :
361 [ # # ]: 0 : if (oport) {
362 : : /* The port is known, remove it before adding it back */
363 : 0 : ovs_list_remove(&oport->p_entries);
364 : 0 : lldpd_port_cleanup(oport, 1);
365 : 0 : free(oport);
366 : : }
367 : :
368 [ # # ]: 0 : if (ochassis) {
369 : 0 : lldpd_move_chassis(ochassis, chassis);
370 : 0 : chassis = ochassis;
371 : : } else {
372 : : /* Chassis not known, add it */
373 [ # # ]: 0 : VLOG_DBG("unknown chassis, add it to the list");
374 : 0 : chassis->c_index = ++cfg->g_lastrid;
375 : 0 : chassis->c_refcount = 0;
376 : 0 : ovs_list_push_back(&cfg->g_chassis, &chassis->list);
377 : 0 : listsize = ovs_list_size(&cfg->g_chassis);
378 [ # # ]: 0 : VLOG_DBG("%"PRIuSIZE " different systems are known", listsize);
379 : : }
380 : :
381 : : /* Add port */
382 : 0 : port->p_lastchange = port->p_lastupdate = time_now();
383 : 0 : port->p_lastframe = xmalloc(s + sizeof(struct lldpd_frame));
384 : 0 : port->p_lastframe->size = s;
385 : 0 : memcpy(port->p_lastframe->frame, frame, s);
386 : 0 : ovs_list_insert(&hw->h_rports, &port->p_entries);
387 : :
388 : 0 : port->p_chassis = chassis;
389 : 0 : port->p_chassis->c_refcount++;
390 : : /* Several cases are possible :
391 : : * 1. chassis is new, its refcount was 0. It is now attached
392 : : * to this port, its refcount is 1.
393 : : * 2. chassis already exists and was attached to another
394 : : * port, we increase its refcount accordingly.
395 : : * 3. chassis already exists and was attached to the same
396 : : * port, its refcount was decreased with
397 : : * lldpd_port_cleanup() and is now increased again.
398 : : *
399 : : * In all cases, if the port already existed, it has been
400 : : * freed with lldpd_port_cleanup() and therefore, the refcount
401 : : * of the chassis that was attached to it is decreased.
402 : : */
403 : 0 : i = ovs_list_size(&hw->h_rports);
404 [ # # ]: 0 : VLOG_DBG("%"PRIuSIZE " neighbors for %s", i, hw->h_ifname);
405 : :
406 [ # # ]: 0 : if (!oport) {
407 : 0 : hw->h_insert_cnt++;
408 : : }
409 : :
410 : 0 : return;
411 : : }
412 : :
413 : : static void
414 : 0 : lldpd_hide_ports(struct lldpd *cfg,
415 : : struct lldpd_hardware *hw,
416 : : int mask) {
417 : : struct lldpd_port *port;
418 : : int protocols[LLDPD_MODE_MAX + 1];
419 : : char buffer[256];
420 : 0 : bool found = false;
421 : : int i, j, k;
422 : : unsigned int min;
423 : :
424 [ # # ]: 0 : VLOG_DBG("apply smart filter for port %s", hw->h_ifname);
425 : :
426 : : /* Compute the number of occurrences of each protocol */
427 [ # # ]: 0 : for (i = 0; i <= LLDPD_MODE_MAX; i++) {
428 : 0 : protocols[i] = 0;
429 : : }
430 : :
431 [ # # ]: 0 : LIST_FOR_EACH (port, p_entries, &hw->h_rports) {
432 : 0 : protocols[port->p_protocol]++;
433 : : }
434 : :
435 : : /* Turn the protocols[] array into an array of
436 : : * enabled/disabled protocols. 1 means enabled, 0
437 : : * means disabled.
438 : : */
439 : 0 : min = (unsigned int) - 1;
440 [ # # ]: 0 : for (i = 0; i <= LLDPD_MODE_MAX; i++) {
441 [ # # ][ # # ]: 0 : if (protocols[i] && (protocols[i] < min)) {
442 : 0 : min = protocols[i];
443 : : }
444 : : }
445 [ # # ]: 0 : for (i = 0; i <= LLDPD_MODE_MAX; i++) {
446 [ # # ][ # # ]: 0 : if (protocols[i] == min && !found) {
447 : : /* If we need a tie breaker, we take the first protocol only */
448 [ # # ]: 0 : if (cfg->g_config.c_smart & mask &
449 : : (SMART_OUTGOING_ONE_PROTO | SMART_INCOMING_ONE_PROTO)) {
450 : 0 : found = true;
451 : : }
452 : 0 : protocols[i] = 1;
453 : : } else {
454 : 0 : protocols[i] = 0;
455 : : }
456 : : }
457 : :
458 : : /* We set the p_hidden flag to 1 if the protocol is disabled */
459 [ # # ]: 0 : LIST_FOR_EACH (port, p_entries, &hw->h_rports) {
460 [ # # ]: 0 : if (mask == SMART_OUTGOING) {
461 : 0 : port->p_hidden_out = protocols[port->p_protocol] ? false : true;
462 : : } else {
463 : 0 : port->p_hidden_in = protocols[port->p_protocol] ? false : true;
464 : : }
465 : : }
466 : :
467 : : /* If we want only one neighbor, we take the first one */
468 [ # # ]: 0 : if (cfg->g_config.c_smart & mask &
469 : : (SMART_OUTGOING_ONE_NEIGH | SMART_INCOMING_ONE_NEIGH)) {
470 : 0 : found = false;
471 : :
472 [ # # ]: 0 : LIST_FOR_EACH (port, p_entries, &hw->h_rports) {
473 [ # # ]: 0 : if (mask == SMART_OUTGOING) {
474 [ # # ]: 0 : if (found) {
475 : 0 : port->p_hidden_out = true;
476 : : }
477 [ # # ]: 0 : if (!port->p_hidden_out) {
478 : 0 : found = true;
479 : : }
480 : : }
481 [ # # ]: 0 : if (mask == SMART_INCOMING) {
482 [ # # ]: 0 : if (found) {
483 : 0 : port->p_hidden_in = true;
484 : : }
485 [ # # ]: 0 : if (!port->p_hidden_in) {
486 : 0 : found = true;
487 : : }
488 : : }
489 : : }
490 : : }
491 : :
492 : : /* Print a debug message summarizing the operation */
493 [ # # ]: 0 : for (i = 0; i <= LLDPD_MODE_MAX; i++) {
494 : 0 : protocols[i] = 0;
495 : : }
496 : :
497 : 0 : k = j = 0;
498 [ # # ]: 0 : LIST_FOR_EACH (port, p_entries, &hw->h_rports) {
499 [ # # ][ # # ]: 0 : if (!((mask == SMART_OUTGOING && port->p_hidden_out) ||
[ # # ]
500 [ # # ]: 0 : (mask == SMART_INCOMING && port->p_hidden_in))) {
501 : 0 : k++;
502 : 0 : protocols[port->p_protocol] = 1;
503 : : }
504 : 0 : j++;
505 : : }
506 : :
507 : 0 : buffer[0] = '\0';
508 [ # # ]: 0 : for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
509 [ # # ][ # # ]: 0 : if (cfg->g_protocols[i].enabled &&
510 : 0 : protocols[cfg->g_protocols[i].mode]) {
511 [ # # ]: 0 : if (strlen(buffer) +
512 : 0 : strlen(cfg->g_protocols[i].name) + 3 > sizeof(buffer)) {
513 : : /* Unlikely, our buffer is too small */
514 : 0 : memcpy(buffer + sizeof(buffer) - 4, "...", 4);
515 : 0 : break;
516 : : }
517 [ # # ]: 0 : if (buffer[0]) {
518 : 0 : strncat(buffer, ", ", 2);
519 : 0 : strncat(buffer, cfg->g_protocols[i].name,
520 : 0 : strlen(cfg->g_protocols[i].name));
521 : : }
522 : : }
523 : : }
524 [ # # ][ # # ]: 0 : VLOG_DBG("%s: %s: %d visible neighbors (out of %d)",
525 : : hw->h_ifname,
526 : : (mask == SMART_OUTGOING) ? "out filter" : "in filter",
527 : : k, j);
528 [ # # ][ # # ]: 0 : VLOG_DBG("%s: protocols: %s",
529 : : hw->h_ifname, buffer[0] ? buffer : "(none)");
530 : 0 : }
531 : :
532 : : /* Hide unwanted ports depending on smart mode set by the user */
533 : : static void
534 : 0 : lldpd_hide_all(struct lldpd *cfg)
535 : : {
536 : : struct lldpd_hardware *hw;
537 : :
538 [ # # ]: 0 : if (!cfg->g_config.c_smart) {
539 : 0 : return;
540 : : }
541 : :
542 [ # # ]: 0 : VLOG_DBG("apply smart filter results on all ports");
543 : :
544 [ # # ]: 0 : LIST_FOR_EACH (hw, h_entries, &cfg->g_hardware) {
545 [ # # ]: 0 : if (cfg->g_config.c_smart & SMART_INCOMING_FILTER) {
546 : 0 : lldpd_hide_ports(cfg, hw, SMART_INCOMING);
547 : : }
548 [ # # ]: 0 : if (cfg->g_config.c_smart & SMART_OUTGOING_FILTER) {
549 : 0 : lldpd_hide_ports(cfg, hw, SMART_OUTGOING);
550 : : }
551 : : }
552 : : }
553 : :
554 : : void
555 : 0 : lldpd_recv(struct lldpd *cfg,
556 : : struct lldpd_hardware *hw,
557 : : char *buffer,
558 : : size_t bufSize)
559 : : {
560 : 0 : int n = bufSize;
561 : :
562 [ # # ]: 0 : VLOG_DBG("receive a frame on %s", hw->h_ifname);
563 [ # # ]: 0 : if (cfg->g_config.c_paused) {
564 [ # # ]: 0 : VLOG_DBG("paused, ignore the frame on %s", hw->h_ifname);
565 : 0 : return;
566 : : }
567 : 0 : hw->h_rx_cnt++;
568 [ # # ]: 0 : VLOG_DBG("decode received frame on %s h_rx_cnt=%" PRIu64,
569 : : hw->h_ifname, hw->h_rx_cnt);
570 : 0 : lldpd_decode(cfg, buffer, n, hw);
571 : 0 : lldpd_hide_all(cfg); /* Immediatly hide */
572 : : }
573 : :
574 : : uint32_t
575 : 0 : lldpd_send(struct lldpd_hardware *hw, struct dp_packet *p)
576 : : {
577 : 0 : struct lldpd *cfg = hw->h_cfg;
578 : : struct lldpd_port *port;
579 : 0 : int i, sent = 0;
580 : 0 : int lldp_size = 0;
581 : :
582 [ # # ][ # # ]: 0 : if (cfg->g_config.c_receiveonly || cfg->g_config.c_paused) {
583 : 0 : return 0;
584 : : }
585 : : #ifndef _WIN32
586 [ # # ]: 0 : if ((hw->h_flags & IFF_RUNNING) == 0) {
587 : 0 : return 0;
588 : : }
589 : : #endif
590 : :
591 [ # # ]: 0 : for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
592 [ # # ]: 0 : if (!cfg->g_protocols[i].enabled) {
593 : 0 : continue;
594 : : }
595 : :
596 : : /* We send only if we have at least one remote system
597 : : * speaking this protocol or if the protocol is forced */
598 [ # # ]: 0 : if (cfg->g_protocols[i].enabled > 1) {
599 [ # # ]: 0 : if ((lldp_size = cfg->g_protocols[i].send(cfg, hw, p)) != -E2BIG) {
600 : 0 : sent++;
601 : 0 : continue;
602 : : } else {
603 [ # # ]: 0 : VLOG_DBG("send PDU on %s failed E2BIG", hw->h_ifname);
604 : 0 : continue;
605 : : }
606 : : }
607 : :
608 [ # # ]: 0 : LIST_FOR_EACH (port, p_entries, &hw->h_rports) {
609 : : /* If this remote port is disabled, we don't consider it */
610 [ # # ]: 0 : if (port->p_hidden_out) {
611 : 0 : continue;
612 : : }
613 [ # # ]: 0 : if (port->p_protocol == cfg->g_protocols[i].mode) {
614 [ # # ]: 0 : VLOG_DBG("send PDU on %s with protocol %s",
615 : : hw->h_ifname, cfg->g_protocols[i].name);
616 : 0 : lldp_size = cfg->g_protocols[i].send(cfg, hw, p);
617 : 0 : sent++;
618 : 0 : break;
619 : : }
620 : : }
621 : : }
622 : :
623 [ # # ]: 0 : if (!sent) {
624 : : /* Nothing was sent for this port, let's speak the first
625 : : * available protocol.
626 : : */
627 [ # # ]: 0 : for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
628 [ # # ]: 0 : if (!cfg->g_protocols[i].enabled) {
629 : 0 : continue;
630 : : }
631 [ # # ]: 0 : VLOG_DBG("fallback to protocol %s for %s",
632 : : cfg->g_protocols[i].name, hw->h_ifname);
633 : 0 : lldp_size = cfg->g_protocols[i].send(cfg, hw, p);
634 : 0 : break;
635 : : }
636 [ # # ]: 0 : if (cfg->g_protocols[i].mode == 0) {
637 [ # # ]: 0 : VLOG_WARN("no protocol enabled, dunno what to send");
638 : : }
639 : : }
640 : :
641 : 0 : return lldp_size;
642 : : }
|