]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/daemon/interfaces-linux.c
interfaces: include "netinet/in.h" before kernel headers
[thirdparty/lldpd.git] / src / daemon / interfaces-linux.c
CommitLineData
4b292b55 1/* -*- mode: c; c-file-style: "openbsd" -*- */
6e75df87
VB
2/*
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 *
51434125 5 * Permission to use, copy, modify, and/or distribute this software for any
6e75df87
VB
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
6e75df87
VB
18#include "lldpd.h"
19
20#include <stdio.h>
21#include <unistd.h>
78c9dfde 22#include <inttypes.h>
6e75df87
VB
23#include <errno.h>
24#include <sys/ioctl.h>
d7460a6f
ALG
25#if defined(__clang__)
26#pragma clang diagnostic push
27#pragma clang diagnostic ignored "-Wdocumentation"
28#endif
217b9531 29#include <netinet/in.h>
6e75df87
VB
30#include <linux/if_vlan.h>
31#include <linux/if_bonding.h>
32#include <linux/if_bridge.h>
33#include <linux/wireless.h>
34#include <linux/sockios.h>
6e75df87 35#include <linux/if_packet.h>
e12c2365 36#include <linux/ethtool.h>
d7460a6f
ALG
37#if defined(__clang__)
38#pragma clang diagnostic pop
39#endif
6e75df87
VB
40
41#define SYSFS_PATH_MAX 256
42#define MAX_PORTS 1024
43#define MAX_BRIDGES 1024
44
fc5526da
VB
45static int
46only_lldp(struct lldpd *cfg)
47{
48 int lldp_enabled = 0;
49 int other_enabled = 0;
50 size_t i;
51 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
52 if (cfg->g_protocols[i].mode == LLDPD_MODE_LLDP)
53 lldp_enabled = cfg->g_protocols[i].enabled;
54 else other_enabled = other_enabled || cfg->g_protocols[i].enabled;
55 }
56 return lldp_enabled && !other_enabled;
57
58}
59
88bc404f
VB
60static int
61iflinux_eth_init(struct lldpd *cfg, struct lldpd_hardware *hardware)
62{
e735a319 63 int fd;
88bc404f
VB
64
65 log_debug("interfaces", "initialize ethernet device %s",
66 hardware->h_ifname);
fc5526da
VB
67 if ((fd = priv_iface_init(hardware->h_ifindex, hardware->h_ifname,
68 only_lldp(cfg)?ETH_P_LLDP:ETH_P_ALL)) == -1)
88bc404f
VB
69 return -1;
70 hardware->h_sendfd = fd; /* Send */
71
88bc404f
VB
72 interfaces_setup_multicast(cfg, hardware->h_ifname, 0);
73
74 levent_hardware_add_fd(hardware, fd); /* Receive */
75 log_debug("interfaces", "interface %s initialized (fd=%d)", hardware->h_ifname,
76 fd);
77 return 0;
78}
79
22e8cd65
VB
80/* Generic ethernet send/receive */
81static int
82iflinux_eth_send(struct lldpd *cfg, struct lldpd_hardware *hardware,
83 char *buffer, size_t size)
84{
85 log_debug("interfaces", "send PDU to ethernet device %s (fd=%d)",
86 hardware->h_ifname, hardware->h_sendfd);
87 return write(hardware->h_sendfd,
88 buffer, size);
89}
90
91static int
462ef2ce
VB
92iflinux_generic_recv(struct lldpd_hardware *hardware,
93 int fd, char *buffer, size_t size,
94 struct sockaddr_ll *from)
22e8cd65 95{
54cccdd4
VB
96 int n, retry = 0;
97 socklen_t fromlen;
22e8cd65 98
54cccdd4
VB
99retry:
100 fromlen = sizeof(*from);
101 memset(from, 0, fromlen);
462ef2ce
VB
102 if ((n = recvfrom(fd, buffer, size, 0,
103 (struct sockaddr *)from,
22e8cd65 104 &fromlen)) == -1) {
54cccdd4
VB
105 if (errno == EAGAIN && retry == 0) {
106 /* There may be an error queued in the socket. Clear it and retry. */
6c3697f2 107 levent_recv_error(fd, hardware->h_ifname);
54cccdd4
VB
108 retry++;
109 goto retry;
110 }
afd49b83
VB
111 if (errno == ENETDOWN) {
112 log_debug("interfaces", "error while receiving frame on %s (network down)",
113 hardware->h_ifname);
114 } else {
115 log_warn("interfaces", "error while receiving frame on %s (retry: %d)",
116 hardware->h_ifname, retry);
117 hardware->h_rx_discarded_cnt++;
118 }
22e8cd65
VB
119 return -1;
120 }
462ef2ce
VB
121 if (from->sll_pkttype == PACKET_OUTGOING)
122 return -1;
123 return n;
124}
125
126static int
127iflinux_eth_recv(struct lldpd *cfg, struct lldpd_hardware *hardware,
128 int fd, char *buffer, size_t size)
129{
130 int n;
54cccdd4 131 struct sockaddr_ll from;
462ef2ce
VB
132
133 log_debug("interfaces", "receive PDU from ethernet device %s",
134 hardware->h_ifname);
135 if ((n = iflinux_generic_recv(hardware, fd, buffer, size, &from)) == -1)
22e8cd65
VB
136 return -1;
137 return n;
138}
139
140static int
141iflinux_eth_close(struct lldpd *cfg, struct lldpd_hardware *hardware)
142{
143 log_debug("interfaces", "close ethernet device %s",
144 hardware->h_ifname);
145 interfaces_setup_multicast(cfg, hardware->h_ifname, 1);
146 return 0;
147}
148
149static struct lldpd_ops eth_ops = {
150 .send = iflinux_eth_send,
151 .recv = iflinux_eth_recv,
152 .cleanup = iflinux_eth_close,
153};
154
6e75df87 155static int
adbb6e54
VB
156iflinux_is_bridge(struct lldpd *cfg,
157 struct interfaces_device_list *interfaces,
158 struct interfaces_device *iface)
6e75df87 159{
16eacc5b 160#ifdef ENABLE_OLDIES
adbb6e54 161 struct interfaces_device *port;
6e75df87
VB
162 char path[SYSFS_PATH_MAX];
163 int f;
164
adbb6e54
VB
165 if ((snprintf(path, SYSFS_PATH_MAX,
166 SYSFS_CLASS_NET "%s/" SYSFS_BRIDGE_FDB,
167 iface->name)) >= SYSFS_PATH_MAX)
6f8925be 168 log_warnx("interfaces", "path truncated");
adbb6e54 169 if ((f = priv_open(path)) < 0)
31c9173a 170 return 0;
6e75df87 171 close(f);
adbb6e54
VB
172
173 /* Also grab all ports */
174 TAILQ_FOREACH(port, interfaces, next) {
175 if (port->upper) continue;
176 if (snprintf(path, SYSFS_PATH_MAX,
177 SYSFS_CLASS_NET "%s/" SYSFS_BRIDGE_PORT_SUBDIR "/%s/port_no",
178 iface->name, port->name) >= SYSFS_PATH_MAX)
179 log_warnx("interfaces", "path truncated");
180 if ((f = priv_open(path)) < 0)
181 continue;
182 log_debug("interfaces",
183 "port %s is bridged to %s",
184 port->name, iface->name);
185 port->upper = iface;
186 close(f);
187 }
188
6e75df87 189 return 1;
16eacc5b
VB
190#else
191 return 0;
192#endif
6e75df87
VB
193}
194
195static int
adbb6e54
VB
196iflinux_is_vlan(struct lldpd *cfg,
197 struct interfaces_device_list *interfaces,
198 struct interfaces_device *iface)
6e75df87 199{
16eacc5b 200#ifdef ENABLE_OLDIES
b0cb07f7 201 struct vlan_ioctl_args ifv = {};
6e75df87 202 ifv.cmd = GET_VLAN_REALDEV_NAME_CMD;
adbb6e54
VB
203 strlcpy(ifv.device1, iface->name, sizeof(ifv.device1));
204 if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) >= 0) {
205 /* This is a VLAN, get the lower interface and the VID */
206 struct interfaces_device *lower =
207 interfaces_nametointerface(interfaces, ifv.u.device2);
208 if (!lower) {
209 log_debug("interfaces",
210 "unable to find lower interface for VLAN %s",
211 iface->name);
212 return 0;
213 }
6e75df87 214
adbb6e54
VB
215 memset(&ifv, 0, sizeof(ifv));
216 ifv.cmd = GET_VLAN_VID_CMD;
217 strlcpy(ifv.device1, iface->name, sizeof(ifv.device1));
218 if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) < 0) {
219 log_debug("interfaces",
220 "unable to find VID for VLAN %s",
221 iface->name);
222 return 0;
223 }
6e75df87 224
adbb6e54 225 iface->lower = lower;
626ea361 226 bitmap_set(iface->vlan_bmap, ifv.u.VID);
6e75df87 227 return 1;
adbb6e54 228 }
16eacc5b 229#endif
6e75df87
VB
230 return 0;
231}
232
233static int
adbb6e54
VB
234iflinux_is_bond(struct lldpd *cfg,
235 struct interfaces_device_list *interfaces,
236 struct interfaces_device *master)
6e75df87 237{
16eacc5b 238#ifdef ENABLE_OLDIES
f5a0a15e
VB
239 /* Shortcut if we detect the new team driver. Upper and lower links
240 * should already be set with netlink in this case. */
241 if (master->driver && !strcmp(master->driver, "team")) {
242 return 1;
243 }
244
b0cb07f7
VB
245 struct ifreq ifr = {};
246 struct ifbond ifb = {};
c557a63b 247 strlcpy(ifr.ifr_name, master->name, sizeof(ifr.ifr_name));
8f88ff70 248 ifr.ifr_data = (char *)&ifb;
6e75df87
VB
249 if (ioctl(cfg->g_sock, SIOCBONDINFOQUERY, &ifr) >= 0) {
250 while (ifb.num_slaves--) {
adbb6e54 251 struct ifslave ifs;
6e75df87
VB
252 memset(&ifr, 0, sizeof(ifr));
253 memset(&ifs, 0, sizeof(ifs));
c557a63b 254 strlcpy(ifr.ifr_name, master->name, sizeof(ifr.ifr_name));
8f88ff70 255 ifr.ifr_data = (char *)&ifs;
6e75df87 256 ifs.slave_id = ifb.num_slaves;
adbb6e54
VB
257 if (ioctl(cfg->g_sock, SIOCBONDSLAVEINFOQUERY, &ifr) >= 0) {
258 struct interfaces_device *slave =
259 interfaces_nametointerface(interfaces,
260 ifs.slave_name);
261 if (slave == NULL) continue;
262 if (slave->upper) continue;
263 log_debug("interfaces",
264 "interface %s is enslaved to %s",
265 slave->name, master->name);
266 slave->upper = master;
6e75df87
VB
267 }
268 }
adbb6e54 269 return 1;
6e75df87 270 }
16eacc5b 271#endif
6e75df87
VB
272 return 0;
273}
274
2d8bd087
VB
275/**
276 * Get permanent MAC from ethtool.
277 *
278 * Return 0 on success, -1 on error.
279 */
280static int
281iflinux_get_permanent_mac_ethtool(struct lldpd *cfg,
282 struct interfaces_device_list *interfaces,
283 struct interfaces_device *iface)
284{
8505c295 285 int ret = -1;
2d8bd087 286 struct ifreq ifr = {};
8505c295
VB
287 struct ethtool_perm_addr *epaddr = calloc(sizeof(struct ethtool_perm_addr) + ETHER_ADDR_LEN, 1);
288 if (epaddr == NULL) goto end;
2d8bd087
VB
289
290 strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
8505c295
VB
291 epaddr->cmd = ETHTOOL_GPERMADDR;
292 epaddr->size = ETHER_ADDR_LEN;
293 ifr.ifr_data = (caddr_t)epaddr;
2d8bd087
VB
294 if (ioctl(cfg->g_sock, SIOCETHTOOL, &ifr) == -1) {
295 static int once = 0;
296 if (errno == EPERM && !once) {
822804ac 297 log_warnx("interfaces",
2d8bd087
VB
298 "no permission to get permanent MAC address for %s (requires 2.6.19+)",
299 iface->name);
300 once = 1;
8505c295 301 goto end;
2d8bd087
VB
302 }
303 if (errno != EPERM)
c4c9f15a 304 log_warn("interfaces", "cannot get permanent MAC address for %s",
2d8bd087 305 iface->name);
8505c295 306 goto end;
2d8bd087 307 }
8505c295
VB
308 if (epaddr->data[0] != 0 ||
309 epaddr->data[1] != 0 ||
310 epaddr->data[2] != 0 ||
311 epaddr->data[3] != 0 ||
312 epaddr->data[4] != 0 ||
313 epaddr->data[5] != 0) {
314 memcpy(iface->address, epaddr->data, ETHER_ADDR_LEN);
315 ret = 0;
316 goto end;
2d8bd087 317 }
c4c9f15a 318 log_debug("interfaces", "cannot get permanent MAC for %s (all 0)", iface->name);
8505c295
VB
319 end:
320 free(epaddr);
321 return ret;
2d8bd087
VB
322}
323
324/**
325 * Get permanent MAC address for a bond device.
326 */
1a3ec373 327static void
2d8bd087 328iflinux_get_permanent_mac_bond(struct lldpd *cfg,
01293dc4
VB
329 struct interfaces_device_list *interfaces,
330 struct interfaces_device *iface)
331{
2d8bd087 332 struct interfaces_device *master = iface->upper;
01293dc4
VB
333 int f, state = 0;
334 FILE *netbond;
335 const char *slaveif = "Slave Interface: ";
336 const char *hwaddr = "Permanent HW addr: ";
337 u_int8_t mac[ETHER_ADDR_LEN];
338 char path[SYSFS_PATH_MAX];
339 char line[100];
340
01293dc4
VB
341 /* We have a bond, we need to query it to get real MAC addresses */
342 if (snprintf(path, SYSFS_PATH_MAX, "/proc/net/bonding/%s",
343 master->name) >= SYSFS_PATH_MAX) {
344 log_warnx("interfaces", "path truncated");
345 return;
346 }
347 if ((f = priv_open(path)) < 0) {
348 if (snprintf(path, SYSFS_PATH_MAX, "/proc/self/net/bonding/%s",
349 master->name) >= SYSFS_PATH_MAX) {
350 log_warnx("interfaces", "path truncated");
351 return;
352 }
353 f = priv_open(path);
354 }
355 if (f < 0) {
0b7f8847
VB
356 log_warnx("interfaces",
357 "unable to get permanent MAC address for %s",
2d8bd087 358 iface->name);
01293dc4
VB
359 return;
360 }
361 if ((netbond = fdopen(f, "r")) == NULL) {
362 log_warn("interfaces", "unable to read stream from %s", path);
363 close(f);
364 return;
365 }
366 /* State 0:
367 We parse the file to search "Slave Interface: ". If found, go to
368 state 1.
369 State 1:
370 We parse the file to search "Permanent HW addr: ". If found, we get
371 the mac.
372 */
373 while (fgets(line, sizeof(line), netbond)) {
374 switch (state) {
375 case 0:
376 if (strncmp(line, slaveif, strlen(slaveif)) == 0) {
377 if (line[strlen(line)-1] == '\n')
378 line[strlen(line)-1] = '\0';
379 if (strcmp(iface->name,
380 line + strlen(slaveif)) == 0)
381 state++;
382 }
383 break;
384 case 1:
385 if (strncmp(line, hwaddr, strlen(hwaddr)) == 0) {
386 if (line[strlen(line)-1] == '\n')
387 line[strlen(line)-1] = '\0';
388 if (sscanf(line + strlen(hwaddr),
389 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
390 &mac[0], &mac[1], &mac[2],
391 &mac[3], &mac[4], &mac[5]) !=
392 ETHER_ADDR_LEN) {
393 log_warn("interfaces", "unable to parse %s",
394 line + strlen(hwaddr));
395 fclose(netbond);
396 return;
397 }
398 memcpy(iface->address, mac,
399 ETHER_ADDR_LEN);
400 fclose(netbond);
401 return;
402 }
403 break;
404 }
405 }
2d8bd087 406 log_warnx("interfaces", "unable to find real MAC address for enslaved %s",
01293dc4
VB
407 iface->name);
408 fclose(netbond);
409}
410
2d8bd087
VB
411/**
412 * Get permanent MAC.
413 */
414static void
415iflinux_get_permanent_mac(struct lldpd *cfg,
416 struct interfaces_device_list *interfaces,
417 struct interfaces_device *iface)
418{
419 struct interfaces_device *master = iface->upper;
420
421 if (master == NULL || master->type != IFACE_BOND_T)
422 return;
423 if (iflinux_get_permanent_mac_ethtool(cfg, interfaces, iface) == -1 &&
424 (master->driver == NULL || !strcmp(master->driver, "bonding")))
425 /* Fallback to old method for a bond */
426 iflinux_get_permanent_mac_bond(cfg, interfaces, iface);
427}
428
dd55e649 429#ifdef ENABLE_DOT3
78c9dfde
VB
430#define ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32 (SCHAR_MAX)
431#define ETHTOOL_DECLARE_LINK_MODE_MASK(name) \
432 uint32_t name[ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32]
433
434struct ethtool_link_usettings {
435 struct ethtool_link_settings base;
436 struct {
437 ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
438 ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
439 ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising);
440 } link_modes;
441};
442
e86777ab 443static int
38cbcf2b
VB
444iflinux_ethtool_link_mode_test_bit(unsigned int nr, const uint32_t *mask)
445{
446 if (nr >= 32 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32)
447 return 0;
448 return !!(mask[nr / 32] & (1 << (nr % 32)));
449}
e86777ab 450static void
38cbcf2b
VB
451iflinux_ethtool_link_mode_unset_bit(unsigned int nr, uint32_t *mask)
452{
453 if (nr >= 32 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32)
454 return;
455 mask[nr / 32] &= ~(1 << (nr % 32));
456}
e86777ab 457static int
38cbcf2b
VB
458iflinux_ethtool_link_mode_is_empty(const uint32_t *mask)
459{
460 for (unsigned int i = 0;
461 i < ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32;
462 ++i) {
463 if (mask[i] != 0)
464 return 0;
465 }
466
467 return 1;
468}
469
78c9dfde
VB
470static int
471iflinux_ethtool_glink(struct lldpd *cfg, const char *ifname, struct ethtool_link_usettings *uset) {
472 int rc;
473
474 /* Try with ETHTOOL_GLINKSETTINGS first */
475 struct {
476 struct ethtool_link_settings req;
477 uint32_t link_mode_data[3 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
478 } ecmd;
479 static int8_t nwords = 0;
480 struct ifreq ifr = {};
481 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
482
483 if (nwords == 0) {
484 /* Do a handshake first. We assume that this is device-independant. */
485 memset(&ecmd, 0, sizeof(ecmd));
486 ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
487 ifr.ifr_data = (caddr_t)&ecmd;
488 rc = ioctl(cfg->g_sock, SIOCETHTOOL, &ifr);
489 if (rc == 0) {
490 nwords = -ecmd.req.link_mode_masks_nwords;
491 log_debug("interfaces", "glinksettings nwords is %" PRId8, nwords);
68caeec4
VB
492 } else {
493 static int once = 0;
494 if (errno == EPERM && !once) {
822804ac 495 log_warnx("interfaces",
68caeec4 496 "cannot get ethtool link information "
822804ac
VB
497 "with GLINKSETTINGS (requires 4.9+). "
498 "25G+ speeds may be missing in MAC/PHY TLVs");
68caeec4
VB
499 once = 1;
500 }
501 nwords = -1;
502 }
78c9dfde
VB
503 }
504 if (nwords > 0) {
505 memset(&ecmd, 0, sizeof(ecmd));
506 ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
507 ecmd.req.link_mode_masks_nwords = nwords;
508 ifr.ifr_data = (caddr_t)&ecmd;
509 rc = ioctl(cfg->g_sock, SIOCETHTOOL, &ifr);
510 if (rc == 0) {
511 log_debug("interfaces", "got ethtool results for %s with GLINKSETTINGS",
512 ifname);
513 memcpy(&uset->base, &ecmd.req, sizeof(uset->base));
514 unsigned int u32_offs = 0;
515 memcpy(uset->link_modes.supported,
516 &ecmd.link_mode_data[u32_offs],
517 4 * ecmd.req.link_mode_masks_nwords);
518 u32_offs += ecmd.req.link_mode_masks_nwords;
519 memcpy(uset->link_modes.advertising,
520 &ecmd.link_mode_data[u32_offs],
521 4 * ecmd.req.link_mode_masks_nwords);
522 u32_offs += ecmd.req.link_mode_masks_nwords;
523 memcpy(uset->link_modes.lp_advertising,
524 &ecmd.link_mode_data[u32_offs],
525 4 * ecmd.req.link_mode_masks_nwords);
526 goto end;
527 }
528 }
529
530 /* Try with ETHTOOL_GSET */
531 struct ethtool_cmd ethc;
532 memset(&ethc, 0, sizeof(ethc));
533 ethc.cmd = ETHTOOL_GSET;
534 ifr.ifr_data = (caddr_t)&ethc;
535 rc = ioctl(cfg->g_sock, SIOCETHTOOL, &ifr);
536 if (rc == 0) {
537 /* Do a partial copy (only what we need) */
538 log_debug("interfaces", "got ethtool results for %s with GSET",
539 ifname);
540 memset(uset, 0, sizeof(*uset));
541 uset->base.cmd = ETHTOOL_GSET;
542 uset->base.link_mode_masks_nwords = 1;
543 uset->link_modes.supported[0] = ethc.supported;
544 uset->link_modes.advertising[0] = ethc.advertising;
545 uset->link_modes.lp_advertising[0] = ethc.lp_advertising;
546 uset->base.speed = (ethc.speed_hi << 16) | ethc.speed;
547 uset->base.duplex = ethc.duplex;
548 uset->base.port = ethc.port;
549 uset->base.autoneg = ethc.autoneg;
68caeec4
VB
550 } else {
551 static int once = 0;
552 if (errno == EPERM && !once) {
822804ac 553 log_warnx("interfaces",
68caeec4 554 "cannot get ethtool link information "
822804ac
VB
555 "with GSET (requires 2.6.19+). "
556 "MAC/PHY TLV will be unavailable");
68caeec4
VB
557 once = 1;
558 }
78c9dfde
VB
559 }
560end:
561 return rc;
562}
38cbcf2b 563
6e75df87
VB
564/* Fill up MAC/PHY for a given hardware port */
565static void
78c9dfde 566iflinux_macphy(struct lldpd *cfg, struct lldpd_hardware *hardware)
6e75df87 567{
38cbcf2b 568 struct ethtool_link_usettings uset;
6e75df87
VB
569 struct lldpd_port *port = &hardware->h_lport;
570 int j;
571 int advertised_ethtool_to_rfc3636[][2] = {
38cbcf2b
VB
572 {ETHTOOL_LINK_MODE_10baseT_Half_BIT, LLDP_DOT3_LINK_AUTONEG_10BASE_T},
573 {ETHTOOL_LINK_MODE_10baseT_Full_BIT, LLDP_DOT3_LINK_AUTONEG_10BASET_FD},
574 {ETHTOOL_LINK_MODE_100baseT_Half_BIT, LLDP_DOT3_LINK_AUTONEG_100BASE_TX},
575 {ETHTOOL_LINK_MODE_100baseT_Full_BIT, LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD},
576 {ETHTOOL_LINK_MODE_1000baseT_Half_BIT, LLDP_DOT3_LINK_AUTONEG_1000BASE_T},
577 {ETHTOOL_LINK_MODE_1000baseT_Full_BIT, LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD},
578 {ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD},
579 {ETHTOOL_LINK_MODE_Pause_BIT, LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE},
580 {ETHTOOL_LINK_MODE_Asym_Pause_BIT, LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE},
581 {-1, 0}};
6e75df87 582
6f8925be
VB
583 log_debug("interfaces", "ask ethtool for the appropriate MAC/PHY for %s",
584 hardware->h_ifname);
78c9dfde 585 if (iflinux_ethtool_glink(cfg, hardware->h_ifname, &uset) == 0) {
38cbcf2b
VB
586 port->p_macphy.autoneg_support = iflinux_ethtool_link_mode_test_bit(
587 ETHTOOL_LINK_MODE_Autoneg_BIT, uset.link_modes.supported);
588 port->p_macphy.autoneg_enabled = (uset.base.autoneg == AUTONEG_DISABLE) ? 0 : 1;
589 for (j=0; advertised_ethtool_to_rfc3636[j][0] >= 0; j++) {
590 if (iflinux_ethtool_link_mode_test_bit(
591 advertised_ethtool_to_rfc3636[j][0],
592 uset.link_modes.advertising)) {
a97e3dfe 593 port->p_macphy.autoneg_advertised |=
6e75df87 594 advertised_ethtool_to_rfc3636[j][1];
38cbcf2b
VB
595 iflinux_ethtool_link_mode_unset_bit(
596 advertised_ethtool_to_rfc3636[j][0],
597 uset.link_modes.advertising);
a97e3dfe 598 }
6e75df87 599 }
38cbcf2b
VB
600 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, uset.link_modes.advertising);
601 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_TP_BIT, uset.link_modes.advertising);
602 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_AUI_BIT, uset.link_modes.advertising);
603 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_MII_BIT, uset.link_modes.advertising);
604 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, uset.link_modes.advertising);
605 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_BNC_BIT, uset.link_modes.advertising);
606 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_Pause_BIT, uset.link_modes.advertising);
607 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, uset.link_modes.advertising);
608 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_Backplane_BIT, uset.link_modes.advertising);
609 if (!iflinux_ethtool_link_mode_is_empty(uset.link_modes.advertising)) {
a97e3dfe 610 port->p_macphy.autoneg_advertised |= LLDP_DOT3_LINK_AUTONEG_OTHER;
38cbcf2b
VB
611 }
612 switch (uset.base.speed) {
6e75df87 613 case SPEED_10:
38cbcf2b 614 port->p_macphy.mau_type = (uset.base.duplex == DUPLEX_FULL) ? \
6e75df87 615 LLDP_DOT3_MAU_10BASETFD : LLDP_DOT3_MAU_10BASETHD;
38cbcf2b
VB
616 if (uset.base.port == PORT_BNC) port->p_macphy.mau_type = LLDP_DOT3_MAU_10BASE2;
617 if (uset.base.port == PORT_FIBRE)
618 port->p_macphy.mau_type = (uset.base.duplex == DUPLEX_FULL) ? \
fda729fd 619 LLDP_DOT3_MAU_10BASEFLFD : LLDP_DOT3_MAU_10BASEFLHD;
6e75df87
VB
620 break;
621 case SPEED_100:
38cbcf2b 622 port->p_macphy.mau_type = (uset.base.duplex == DUPLEX_FULL) ? \
6e75df87 623 LLDP_DOT3_MAU_100BASETXFD : LLDP_DOT3_MAU_100BASETXHD;
38cbcf2b
VB
624 if (uset.base.port == PORT_BNC)
625 port->p_macphy.mau_type = (uset.base.duplex == DUPLEX_FULL) ? \
5fa8eaa5 626 LLDP_DOT3_MAU_100BASET2FD : LLDP_DOT3_MAU_100BASET2HD;
38cbcf2b
VB
627 if (uset.base.port == PORT_FIBRE)
628 port->p_macphy.mau_type = (uset.base.duplex == DUPLEX_FULL) ? \
6e75df87
VB
629 LLDP_DOT3_MAU_100BASEFXFD : LLDP_DOT3_MAU_100BASEFXHD;
630 break;
631 case SPEED_1000:
38cbcf2b 632 port->p_macphy.mau_type = (uset.base.duplex == DUPLEX_FULL) ? \
6e75df87 633 LLDP_DOT3_MAU_1000BASETFD : LLDP_DOT3_MAU_1000BASETHD;
38cbcf2b
VB
634 if (uset.base.port == PORT_FIBRE)
635 port->p_macphy.mau_type = (uset.base.duplex == DUPLEX_FULL) ? \
6e75df87
VB
636 LLDP_DOT3_MAU_1000BASEXFD : LLDP_DOT3_MAU_1000BASEXHD;
637 break;
638 case SPEED_10000:
a97e3dfe
VB
639 // For fiber, we tell 10GIGBASEX and for others,
640 // 10GIGBASER. It's not unusual to have 10GIGBASER on
641 // fiber either but we don't have 10GIGBASET for
642 // copper. No good solution.
38cbcf2b
VB
643 port->p_macphy.mau_type = (uset.base.port == PORT_FIBRE) ? \
644 LLDP_DOT3_MAU_10GIGBASELR : LLDP_DOT3_MAU_10GIGBASECX4;
6e75df87 645 break;
38cbcf2b
VB
646 case SPEED_40000:
647 // Same kind of approximation.
648 port->p_macphy.mau_type = (uset.base.port == PORT_FIBRE) ? \
649 LLDP_DOT3_MAU_40GBASELR4 : LLDP_DOT3_MAU_40GBASECR4;
3a59626a 650 break;
38cbcf2b
VB
651 case SPEED_100000:
652 // Ditto
653 port->p_macphy.mau_type = (uset.base.port == PORT_FIBRE) ? \
654 LLDP_DOT3_MAU_100GBASELR4 : LLDP_DOT3_MAU_100GBASECR10;
3a59626a 655 break;
6e75df87 656 }
38cbcf2b 657 if (uset.base.port == PORT_AUI) port->p_macphy.mau_type = LLDP_DOT3_MAU_AUI;
6e75df87 658 }
6e75df87 659}
dd55e649
VB
660#else /* ENABLE_DOT3 */
661static void
662iflinux_macphy(struct lldpd *cfg, struct lldpd_hardware *hardware)
663{
664}
665#endif /* ENABLE_DOT3 */
666
6e75df87 667
2f4ff307 668#ifdef ENABLE_OLDIES
e12c2365
VB
669struct bond_master {
670 char name[IFNAMSIZ];
671 int index;
672};
673
849954d7
VB
674static int
675iface_bond_init(struct lldpd *cfg, struct lldpd_hardware *hardware)
676{
e12c2365 677 struct bond_master *master = hardware->h_data;
e735a319 678 int fd;
849954d7 679 int un = 1;
fc5526da 680 int proto;
849954d7 681
e12c2365 682 if (!master) return -1;
849954d7 683
0da01fd6 684 log_debug("interfaces", "initialize enslaved device %s",
6f8925be
VB
685 hardware->h_ifname);
686
849954d7 687 /* First, we get a socket to the raw physical interface */
fc5526da 688 proto = only_lldp(cfg)?ETH_P_LLDP:ETH_P_ALL;
e735a319 689 if ((fd = priv_iface_init(hardware->h_ifindex,
fc5526da 690 hardware->h_ifname, proto)) == -1)
849954d7
VB
691 return -1;
692 hardware->h_sendfd = fd;
adbb6e54 693 interfaces_setup_multicast(cfg, hardware->h_ifname, 0);
849954d7
VB
694
695 /* Then, we open a raw interface for the master */
0da01fd6 696 log_debug("interfaces", "enslaved device %s has master %s(%d)",
148a1efe 697 hardware->h_ifname, master->name, master->index);
fc5526da 698 if ((fd = priv_iface_init(master->index, master->name, proto)) == -1) {
849954d7
VB
699 close(hardware->h_sendfd);
700 return -1;
701 }
849954d7
VB
702 /* With bonding and older kernels (< 2.6.27) we need to listen
703 * to bond device. We use setsockopt() PACKET_ORIGDEV to get
704 * physical device instead of bond device (works with >=
705 * 2.6.24). */
706 if (setsockopt(fd, SOL_PACKET,
e12c2365
VB
707 PACKET_ORIGDEV, &un, sizeof(un)) == -1) {
708 log_info("interfaces", "unable to setsockopt for master bonding device of %s. "
709 "You will get inaccurate results",
710 hardware->h_ifname);
849954d7 711 }
adbb6e54 712 interfaces_setup_multicast(cfg, master->name, 0);
849954d7 713
ba93c521 714 levent_hardware_add_fd(hardware, hardware->h_sendfd);
d6e889b6 715 levent_hardware_add_fd(hardware, fd);
6f8925be 716 log_debug("interfaces", "interface %s initialized (fd=%d,master=%s[%d])",
849954d7
VB
717 hardware->h_ifname,
718 hardware->h_sendfd,
e12c2365 719 master->name, fd);
849954d7
VB
720 return 0;
721}
722
849954d7
VB
723static int
724iface_bond_recv(struct lldpd *cfg, struct lldpd_hardware *hardware,
725 int fd, char *buffer, size_t size)
726{
727 int n;
54cccdd4 728 struct sockaddr_ll from;
e12c2365 729 struct bond_master *master = hardware->h_data;
849954d7 730
0da01fd6 731 log_debug("interfaces", "receive PDU from enslaved device %s",
6f8925be 732 hardware->h_ifname);
462ef2ce 733 if ((n = iflinux_generic_recv(hardware, fd, buffer, size, &from)) == -1)
849954d7
VB
734 return -1;
735 if (fd == hardware->h_sendfd)
736 /* We received this on the physical interface. */
737 return n;
738 /* We received this on the bonding interface. Is it really for us? */
44002d66 739 if (from.sll_ifindex == hardware->h_ifindex)
849954d7
VB
740 /* This is for us */
741 return n;
e12c2365 742 if (from.sll_ifindex == master->index)
849954d7
VB
743 /* We don't know from which physical interface it comes (kernel
744 * < 2.6.24). In doubt, this is for us. */
745 return n;
746 return -1; /* Not for us */
747}
748
749static int
750iface_bond_close(struct lldpd *cfg, struct lldpd_hardware *hardware)
751{
e12c2365 752 struct bond_master *master = hardware->h_data;
0da01fd6 753 log_debug("interfaces", "closing enslaved device %s",
6f8925be 754 hardware->h_ifname);
adbb6e54
VB
755 interfaces_setup_multicast(cfg, hardware->h_ifname, 1);
756 interfaces_setup_multicast(cfg, master->name, 1);
32945d6a 757 free(hardware->h_data); hardware->h_data = NULL;
849954d7
VB
758 return 0;
759}
760
adbb6e54 761struct lldpd_ops bond_ops = {
5347914e 762 .send = iflinux_eth_send,
adbb6e54
VB
763 .recv = iface_bond_recv,
764 .cleanup = iface_bond_close,
765};
766
e12c2365 767static void
adbb6e54 768iflinux_handle_bond(struct lldpd *cfg, struct interfaces_device_list *interfaces)
849954d7 769{
adbb6e54
VB
770 struct interfaces_device *iface;
771 struct interfaces_device *master;
849954d7 772 struct lldpd_hardware *hardware;
c557a63b 773 struct bond_master *bmaster;
32945d6a 774 int created;
e12c2365 775 TAILQ_FOREACH(iface, interfaces, next) {
adbb6e54 776 if (!(iface->type & IFACE_PHYSICAL_T)) continue;
0fa2254b 777 if (iface->ignore) continue;
adbb6e54 778 if (!iface->upper || !(iface->upper->type & IFACE_BOND_T)) continue;
849954d7 779
adbb6e54 780 master = iface->upper;
0da01fd6 781 log_debug("interfaces", "%s is an acceptable enslaved device (master=%s)",
c557a63b 782 iface->name, master->name);
32945d6a 783 created = 0;
44002d66 784 if ((hardware = lldpd_get_hardware(cfg,
e12c2365 785 iface->name,
32945d6a 786 iface->index)) == NULL) {
849954d7 787 if ((hardware = lldpd_alloc_hardware(cfg,
e12c2365
VB
788 iface->name,
789 iface->index)) == NULL) {
6f8925be 790 log_warnx("interfaces", "Unable to allocate space for %s",
e12c2365
VB
791 iface->name);
792 continue;
793 }
32945d6a
VB
794 created = 1;
795 }
796 if (hardware->h_flags) continue;
797 if (hardware->h_ops != &bond_ops) {
798 if (!created) {
799 log_debug("interfaces",
800 "bond %s is converted from another type of interface",
801 hardware->h_ifname);
802 if (hardware->h_ops && hardware->h_ops->cleanup)
803 hardware->h_ops->cleanup(cfg, hardware);
804 levent_hardware_release(hardware);
805 levent_hardware_init(hardware);
806 }
08ced6b4
VB
807 bmaster = hardware->h_data = calloc(1, sizeof(struct bond_master));
808 if (!bmaster) {
e12c2365
VB
809 log_warn("interfaces", "not enough memory");
810 lldpd_hardware_cleanup(cfg, hardware);
811 continue;
812 }
32945d6a
VB
813 } else bmaster = hardware->h_data;
814 bmaster->index = master->index;
815 strlcpy(bmaster->name, master->name, IFNAMSIZ);
816 if (hardware->h_ops != &bond_ops) {
849954d7 817 if (iface_bond_init(cfg, hardware) != 0) {
6f8925be 818 log_warn("interfaces", "unable to initialize %s",
849954d7
VB
819 hardware->h_ifname);
820 lldpd_hardware_cleanup(cfg, hardware);
821 continue;
822 }
823 hardware->h_ops = &bond_ops;
5347914e 824 hardware->h_mangle = 1;
32945d6a
VB
825 }
826 if (created)
bdfe4193 827 interfaces_helper_add_hardware(cfg, hardware);
32945d6a 828 else
4b292b55 829 lldpd_port_cleanup(&hardware->h_lport, 0);
e12c2365
VB
830
831 hardware->h_flags = iface->flags;
0fa2254b 832 iface->ignore = 1;
849954d7
VB
833
834 /* Get local address */
4e5f34c5 835 memcpy(&hardware->h_lladdr, iface->address, ETHER_ADDR_LEN);
e12c2365 836
36bd79e3 837 /* Fill information about port */
8fbd3195 838 interfaces_helper_port_name_desc(cfg, hardware, iface);
e12c2365 839
849954d7 840 /* Fill additional info */
7a008075 841#ifdef ENABLE_DOT3
e12c2365 842 hardware->h_lport.p_aggregid = master->index;
7a008075 843#endif
e12c2365 844 hardware->h_mtu = iface->mtu ? iface->mtu : 1500;
849954d7
VB
845 }
846}
2f4ff307 847#endif
849954d7 848
adbb6e54 849/* Query each interface to get the appropriate driver */
5994b27d 850static void
adbb6e54
VB
851iflinux_add_driver(struct lldpd *cfg,
852 struct interfaces_device_list *interfaces)
5994b27d 853{
adbb6e54
VB
854 struct interfaces_device *iface;
855 TAILQ_FOREACH(iface, interfaces, next) {
856 struct ethtool_drvinfo ethc = {
857 .cmd = ETHTOOL_GDRVINFO
858 };
859 struct ifreq ifr = {
860 .ifr_data = (caddr_t)&ethc
861 };
862 if (iface->driver) continue;
863
864 strlcpy(ifr.ifr_name, iface->name, IFNAMSIZ);
865 if (ioctl(cfg->g_sock, SIOCETHTOOL, &ifr) == 0) {
866 iface->driver = strdup(ethc.driver);
867 log_debug("interfaces", "driver for %s is `%s`",
868 iface->name, iface->driver);
869 }
5994b27d
VB
870 }
871}
872
adbb6e54 873/* Query each interface to see if it is a wireless one */
e12c2365 874static void
adbb6e54
VB
875iflinux_add_wireless(struct lldpd *cfg,
876 struct interfaces_device_list *interfaces)
f6c4ca4b 877{
adbb6e54
VB
878 struct interfaces_device *iface;
879 TAILQ_FOREACH(iface, interfaces, next) {
b0cb07f7 880 struct iwreq iwr = {};
adbb6e54
VB
881 strlcpy(iwr.ifr_name, iface->name, IFNAMSIZ);
882 if (ioctl(cfg->g_sock, SIOCGIWNAME, &iwr) >= 0) {
883 log_debug("interfaces", "%s is wireless",
884 iface->name);
885 iface->type |= IFACE_WIRELESS_T | IFACE_PHYSICAL_T;
f6c4ca4b 886 }
f6c4ca4b 887 }
adbb6e54 888}
f6c4ca4b 889
adbb6e54
VB
890/* Query each interface to see if it is a bridge */
891static void
892iflinux_add_bridge(struct lldpd *cfg,
893 struct interfaces_device_list *interfaces)
894{
895 struct interfaces_device *iface;
f6c4ca4b 896
adbb6e54
VB
897 TAILQ_FOREACH(iface, interfaces, next) {
898 if (iface->type & (IFACE_PHYSICAL_T|
899 IFACE_VLAN_T|IFACE_BOND_T|IFACE_BRIDGE_T))
900 continue;
901 if (iflinux_is_bridge(cfg, interfaces, iface)) {
902 log_debug("interfaces",
903 "interface %s is a bridge",
904 iface->name);
905 iface->type |= IFACE_BRIDGE_T;
f6c4ca4b 906 }
f6c4ca4b 907 }
f6c4ca4b
VB
908}
909
adbb6e54 910/* Query each interface to see if it is a bond */
f6c4ca4b 911static void
adbb6e54
VB
912iflinux_add_bond(struct lldpd *cfg,
913 struct interfaces_device_list *interfaces)
6e75df87 914{
adbb6e54 915 struct interfaces_device *iface;
e12c2365
VB
916
917 TAILQ_FOREACH(iface, interfaces, next) {
adbb6e54
VB
918 if (iface->type & (IFACE_PHYSICAL_T|IFACE_VLAN_T|
919 IFACE_BOND_T|IFACE_BRIDGE_T))
6e75df87 920 continue;
adbb6e54
VB
921 if (iflinux_is_bond(cfg, interfaces, iface)) {
922 log_debug("interfaces",
923 "interface %s is a bond",
924 iface->name);
925 iface->type |= IFACE_BOND_T;
adbb6e54 926 }
6e75df87 927 }
6e75df87
VB
928}
929
adbb6e54 930/* Query each interface to see if it is a vlan */
e12c2365 931static void
adbb6e54
VB
932iflinux_add_vlan(struct lldpd *cfg,
933 struct interfaces_device_list *interfaces)
6e75df87 934{
adbb6e54 935 struct interfaces_device *iface;
d4e4c804 936
adbb6e54
VB
937 TAILQ_FOREACH(iface, interfaces, next) {
938 if (iface->type & (IFACE_PHYSICAL_T|IFACE_VLAN_T|
939 IFACE_BOND_T|IFACE_BRIDGE_T))
940 continue;
941 if (iflinux_is_vlan(cfg, interfaces, iface)) {
942 log_debug("interfaces",
943 "interface %s is a VLAN",
944 iface->name);
945 iface->type |= IFACE_VLAN_T;
6e75df87
VB
946 }
947 }
948}
31ee070d 949
e12c2365 950static void
adbb6e54
VB
951iflinux_add_physical(struct lldpd *cfg,
952 struct interfaces_device_list *interfaces)
b4ac8083 953{
adbb6e54 954 struct interfaces_device *iface;
45369c0a
VB
955 /* Blacklist some drivers */
956 const char * const *rif;
957 const char * const blacklisted_drivers[] = {
958 "cdc_mbim",
aed57880 959 "vxlan",
45369c0a
VB
960 NULL
961 };
b4ac8083 962
e12c2365 963 TAILQ_FOREACH(iface, interfaces, next) {
adbb6e54
VB
964 if (iface->type & (IFACE_VLAN_T|
965 IFACE_BOND_T|IFACE_BRIDGE_T))
966 continue;
b4ac8083 967
adbb6e54
VB
968 iface->type &= ~IFACE_PHYSICAL_T;
969
970 /* We request that the interface is able to do either multicast
971 * or broadcast to be able to send discovery frames. */
972 if (!(iface->flags & (IFF_MULTICAST|IFF_BROADCAST))) {
973 log_debug("interfaces", "skip %s: not able to do multicast nor broadcast",
974 iface->name);
b4ac8083 975 continue;
adbb6e54 976 }
b4ac8083 977
45369c0a
VB
978 /* Check if the driver is not blacklisted */
979 if (iface->driver) {
980 int skip = 0;
981 for (rif = blacklisted_drivers; *rif; rif++) {
982 if (strcmp(iface->driver, *rif) == 0) {
983 log_debug("interfaces", "skip %s: blacklisted driver",
984 iface->name);
985 skip = 1;
986 break;
987 }
988 }
989 if (skip) continue;
990 }
991
981ee4fe 992 /* If the interface is linked to another one, skip it too. */
a636b31d 993 if (iface->lower && (!iface->driver || (strcmp(iface->driver, "veth") && strcmp(iface->driver, "dsa")))) {
981ee4fe
VB
994 log_debug("interfaces", "skip %s: there is a lower interface (%s)",
995 iface->name, iface->lower->name);
996 continue;
997 }
998
12baf781
VB
999 /* Get the real MAC address (for example, if the interface is enslaved) */
1000 iflinux_get_permanent_mac(cfg, interfaces, iface);
1001
adbb6e54
VB
1002 log_debug("interfaces",
1003 "%s is a physical interface",
1004 iface->name);
1005 iface->type |= IFACE_PHYSICAL_T;
b4ac8083
VB
1006 }
1007}
1008
e12c2365
VB
1009void
1010interfaces_update(struct lldpd *cfg)
1011{
adbb6e54 1012 struct lldpd_hardware *hardware;
281a5cd4
VB
1013 struct interfaces_device_list *interfaces;
1014 struct interfaces_address_list *addresses;
13181ede
VB
1015 interfaces = netlink_get_interfaces(cfg);
1016 addresses = netlink_get_addresses(cfg);
e12c2365
VB
1017 if (interfaces == NULL || addresses == NULL) {
1018 log_warnx("interfaces", "cannot update the list of local interfaces");
0fa2254b 1019 return;
e12c2365
VB
1020 }
1021
adbb6e54
VB
1022 /* Add missing bits to list of interfaces */
1023 iflinux_add_driver(cfg, interfaces);
a2b113ef 1024 if (LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_WLAN)
1025 iflinux_add_wireless(cfg, interfaces);
1026 if (LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_BRIDGE)
1027 iflinux_add_bridge(cfg, interfaces);
adbb6e54
VB
1028 iflinux_add_bond(cfg, interfaces);
1029 iflinux_add_vlan(cfg, interfaces);
1030 iflinux_add_physical(cfg, interfaces);
1031
1032 interfaces_helper_whitelist(cfg, interfaces);
2f4ff307 1033#ifdef ENABLE_OLDIES
adbb6e54 1034 iflinux_handle_bond(cfg, interfaces);
2f4ff307 1035#endif
88bc404f 1036 interfaces_helper_physical(cfg, interfaces,
22e8cd65 1037 &eth_ops,
88bc404f 1038 iflinux_eth_init);
e12c2365 1039#ifdef ENABLE_DOT1
adbb6e54 1040 interfaces_helper_vlan(cfg, interfaces);
e12c2365 1041#endif
68bc4a4d 1042 interfaces_helper_mgmt(cfg, addresses, interfaces);
adbb6e54
VB
1043 interfaces_helper_chassis(cfg, interfaces);
1044
1045 /* Mac/PHY */
1046 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
1047 if (!hardware->h_flags) continue;
78c9dfde 1048 iflinux_macphy(cfg, hardware);
f84199dd 1049 interfaces_helper_promisc(cfg, hardware);
adbb6e54 1050 }
e12c2365 1051}
13181ede
VB
1052
1053void
1054interfaces_cleanup(struct lldpd *cfg)
1055{
1056 netlink_cleanup(cfg);
1057}