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