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