144d362409d5469aed47d19e7908d19bd194493aThomas Graf/*
244d362409d5469aed47d19e7908d19bd194493aThomas Graf * lib/route/link.c	Links (Interfaces)
344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
444d362409d5469aed47d19e7908d19bd194493aThomas Graf *	This library is free software; you can redistribute it and/or
544d362409d5469aed47d19e7908d19bd194493aThomas Graf *	modify it under the terms of the GNU Lesser General Public
644d362409d5469aed47d19e7908d19bd194493aThomas Graf *	License as published by the Free Software Foundation version 2.1
744d362409d5469aed47d19e7908d19bd194493aThomas Graf *	of the License.
844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
98a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
1044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1144d362409d5469aed47d19e7908d19bd194493aThomas Graf
1244d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
1344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @ingroup rtnl
1444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @defgroup link Links (Interfaces)
1544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @brief
1644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
1744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par Link Identification
1844d362409d5469aed47d19e7908d19bd194493aThomas Graf * A link can be identified by either its interface index or by its
1944d362409d5469aed47d19e7908d19bd194493aThomas Graf * name. The kernel favours the interface index but falls back to the
2044d362409d5469aed47d19e7908d19bd194493aThomas Graf * interface name if the interface index is lesser-than 0 for kernels
2144d362409d5469aed47d19e7908d19bd194493aThomas Graf * >= 2.6.11. Therefore you can request changes without mapping a
2244d362409d5469aed47d19e7908d19bd194493aThomas Graf * interface name to the corresponding index first.
2344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
2444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par Changeable Attributes
2544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @anchor link_changeable
2644d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - Link layer address
2744d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - Link layer broadcast address
2844d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - device mapping (ifmap) (>= 2.6.9)
2944d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - MTU (>= 2.6.9)
3044d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - Transmission queue length (>= 2.6.9)
3144d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - Weight (>= 2.6.9)
3244d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - Link name (only via access through interface index) (>= 2.6.9)
3344d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - Flags (>= 2.6.9)
3444d362409d5469aed47d19e7908d19bd194493aThomas Graf *    - IFF_DEBUG
3544d362409d5469aed47d19e7908d19bd194493aThomas Graf *    - IFF_NOTRAILERS
3644d362409d5469aed47d19e7908d19bd194493aThomas Graf *    - IFF_NOARP
3744d362409d5469aed47d19e7908d19bd194493aThomas Graf *    - IFF_DYNAMIC
3844d362409d5469aed47d19e7908d19bd194493aThomas Graf *    - IFF_MULTICAST
3944d362409d5469aed47d19e7908d19bd194493aThomas Graf *    - IFF_PORTSEL
4044d362409d5469aed47d19e7908d19bd194493aThomas Graf *    - IFF_AUTOMEDIA
4144d362409d5469aed47d19e7908d19bd194493aThomas Graf *    - IFF_UP
4244d362409d5469aed47d19e7908d19bd194493aThomas Graf *    - IFF_PROMISC
4344d362409d5469aed47d19e7908d19bd194493aThomas Graf *    - IFF_ALLMULTI
4444d362409d5469aed47d19e7908d19bd194493aThomas Graf *
4544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par Link Flags (linux/if.h)
4644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @anchor link_flags
4744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
4844d362409d5469aed47d19e7908d19bd194493aThomas Graf *   IFF_UP            Status of link (up|down)
4944d362409d5469aed47d19e7908d19bd194493aThomas Graf *   IFF_BROADCAST     Indicates this link allows broadcasting
5044d362409d5469aed47d19e7908d19bd194493aThomas Graf *   IFF_MULTICAST     Indicates this link allows multicasting
5144d362409d5469aed47d19e7908d19bd194493aThomas Graf *   IFF_ALLMULTI      Indicates this link is doing multicast routing
5244d362409d5469aed47d19e7908d19bd194493aThomas Graf *   IFF_DEBUG         Tell the driver to do debugging (currently unused)
5344d362409d5469aed47d19e7908d19bd194493aThomas Graf *   IFF_LOOPBACK      This is the loopback link
5444d362409d5469aed47d19e7908d19bd194493aThomas Graf *   IFF_POINTOPOINT   Point-to-point link
5544d362409d5469aed47d19e7908d19bd194493aThomas Graf *   IFF_NOARP         Link is unable to perform ARP
5644d362409d5469aed47d19e7908d19bd194493aThomas Graf *   IFF_PROMISC       Status of promiscious mode flag
5744d362409d5469aed47d19e7908d19bd194493aThomas Graf *   IFF_MASTER        Used by teql
5844d362409d5469aed47d19e7908d19bd194493aThomas Graf *   IFF_SLAVE         Used by teql
5944d362409d5469aed47d19e7908d19bd194493aThomas Graf *   IFF_PORTSEL       Indicates this link allows port selection
6044d362409d5469aed47d19e7908d19bd194493aThomas Graf *   IFF_AUTOMEDIA     Indicates this link selects port automatically
6144d362409d5469aed47d19e7908d19bd194493aThomas Graf *   IFF_DYNAMIC       Indicates the address of this link is dynamic
6244d362409d5469aed47d19e7908d19bd194493aThomas Graf *   IFF_RUNNING       Link is running and carrier is ok.
6344d362409d5469aed47d19e7908d19bd194493aThomas Graf *   IFF_NOTRAILERS    Unused, BSD compat.
6444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
6544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
6644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par Notes on IFF_PROMISC and IFF_ALLMULTI flags
6744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Although you can query the status of IFF_PROMISC and IFF_ALLMULTI
6844d362409d5469aed47d19e7908d19bd194493aThomas Graf * they do not represent the actual state in the kernel but rather
6944d362409d5469aed47d19e7908d19bd194493aThomas Graf * whether the flag has been enabled/disabled by userspace. The link
7044d362409d5469aed47d19e7908d19bd194493aThomas Graf * may be in promiscious mode even if IFF_PROMISC is not set in a link
7144d362409d5469aed47d19e7908d19bd194493aThomas Graf * dump request response because promiscity might be needed by the driver
7244d362409d5469aed47d19e7908d19bd194493aThomas Graf * for a period of time.
7344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
7444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @note The unit of the transmission queue length depends on the
7544d362409d5469aed47d19e7908d19bd194493aThomas Graf *       link type, a common unit is \a packets.
7644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
7744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par 1) Retrieving information about available links
7844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
7944d362409d5469aed47d19e7908d19bd194493aThomas Graf * // The first step is to retrieve a list of all available interfaces within
8044d362409d5469aed47d19e7908d19bd194493aThomas Graf * // the kernel and put them into a cache.
811155370f520cb64657e25153255cf7dc1424317fThomas Graf * struct nl_cache *cache = rtnl_link_alloc_cache(sk);
8244d362409d5469aed47d19e7908d19bd194493aThomas Graf *
8344d362409d5469aed47d19e7908d19bd194493aThomas Graf * // In a second step, a specific link may be looked up by either interface
8444d362409d5469aed47d19e7908d19bd194493aThomas Graf * // index or interface name.
8544d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct rtnl_link *link = rtnl_link_get_by_name(cache, "lo");
8644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
8744d362409d5469aed47d19e7908d19bd194493aThomas Graf * // rtnl_link_get_by_name() is the short version for translating the
8844d362409d5469aed47d19e7908d19bd194493aThomas Graf * // interface name to an interface index first like this:
8944d362409d5469aed47d19e7908d19bd194493aThomas Graf * int ifindex = rtnl_link_name2i(cache, "lo");
9044d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct rtnl_link *link = rtnl_link_get(cache, ifindex);
9144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
9244d362409d5469aed47d19e7908d19bd194493aThomas Graf * // After successful usage, the object must be given back to the cache
9344d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_link_put(link);
9444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
9544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
9644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par 2) Changing link attributes
9744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
9844d362409d5469aed47d19e7908d19bd194493aThomas Graf * // In order to change any attributes of an existing link, we must allocate
9944d362409d5469aed47d19e7908d19bd194493aThomas Graf * // a new link to hold the change requests:
10044d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct rtnl_link *request = rtnl_link_alloc();
10144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
10244d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Now we can go on and specify the attributes we want to change:
10344d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_link_set_weight(request, 300);
10444d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_link_set_mtu(request, 1360);
10544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
10644d362409d5469aed47d19e7908d19bd194493aThomas Graf * // We can also shut an interface down administratively
10744d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_link_unset_flags(request, rtnl_link_str2flags("up"));
10844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
10944d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Actually, we should know which link to change, so let's look it up
11044d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct rtnl_link *old = rtnl_link_get(cache, "eth0");
11144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
11244d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Two ways exist to commit this change request, the first one is to
11344d362409d5469aed47d19e7908d19bd194493aThomas Graf * // build the required netlink message and send it out in one single
11444d362409d5469aed47d19e7908d19bd194493aThomas Graf * // step:
1151155370f520cb64657e25153255cf7dc1424317fThomas Graf * rtnl_link_change(sk, old, request);
11644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
11744d362409d5469aed47d19e7908d19bd194493aThomas Graf * // An alternative way is to build the netlink message and send it
11844d362409d5469aed47d19e7908d19bd194493aThomas Graf * // out yourself using nl_send_auto_complete()
11944d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct nl_msg *msg = rtnl_link_build_change_request(old, request);
1201155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_send_auto_complete(sk, nlmsg_hdr(msg));
12144d362409d5469aed47d19e7908d19bd194493aThomas Graf * nlmsg_free(msg);
12244d362409d5469aed47d19e7908d19bd194493aThomas Graf *
12344d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Don't forget to give back the link object ;->
12444d362409d5469aed47d19e7908d19bd194493aThomas Graf * rtnl_link_put(old);
12544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
126a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf *
127a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * @par 3) Link Type Specific Attributes
128a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * @code
129a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * // Some link types offer additional parameters and statistics specific
130a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * // to their type. F.e. a VLAN link can be configured like this:
131a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * //
132a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * // Allocate a new link and set the info type to "vlan". This is required
133a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * // to prepare the link to hold vlan specific attributes.
134a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * struct rtnl_link *request = rtnl_link_alloc();
135a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * rtnl_link_set_info_type(request, "vlan");
136a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf *
137a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * // Now vlan specific attributes can be set:
138a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * rtnl_link_vlan_set_id(request, 10);
139a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * rtnl_link_vlan_set_ingress_map(request, 2, 8);
140a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf *
141a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * // Of course the attributes can also be read, check the info type
142a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * // to make sure you are using the right access functions:
143a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * char *type = rtnl_link_get_info_type(link);
144a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * if (!strcmp(type, "vlan"))
145a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * 	int id = rtnl_link_vlan_get_id(link);
146a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * @endcode
14744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
14844d362409d5469aed47d19e7908d19bd194493aThomas Graf */
14944d362409d5469aed47d19e7908d19bd194493aThomas Graf
15044d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-local.h>
15144d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/netlink.h>
15244d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/attr.h>
15344d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/utils.h>
15444d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/object.h>
15544d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/rtnl.h>
15644d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/link.h>
157a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf#include <netlink/route/link/info-api.h>
15844d362409d5469aed47d19e7908d19bd194493aThomas Graf
15944d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @cond SKIP */
16044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_ATTR_MTU     0x0001
16144d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_ATTR_LINK    0x0002
16244d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_ATTR_TXQLEN  0x0004
16344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_ATTR_WEIGHT  0x0008
16444d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_ATTR_MASTER  0x0010
16544d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_ATTR_QDISC   0x0020
16644d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_ATTR_MAP     0x0040
16744d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_ATTR_ADDR    0x0080
16844d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_ATTR_BRD     0x0100
16944d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_ATTR_FLAGS   0x0200
17044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_ATTR_IFNAME  0x0400
17144d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_ATTR_IFINDEX 0x0800
17244d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_ATTR_FAMILY  0x1000
17344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_ATTR_ARPTYPE 0x2000
17444d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_ATTR_STATS   0x4000
17544d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_ATTR_CHANGE  0x8000
1763ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf#define LINK_ATTR_OPERSTATE 0x10000
1773ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf#define LINK_ATTR_LINKMODE  0x20000
178a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf#define LINK_ATTR_LINKINFO  0x40000
17944d362409d5469aed47d19e7908d19bd194493aThomas Graf
18044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_cache_ops rtnl_link_ops;
18144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_object_ops link_obj_ops;
18244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @endcond */
18344d362409d5469aed47d19e7908d19bd194493aThomas Graf
184a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Grafstatic void release_link_info(struct rtnl_link *link)
185a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf{
186a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	struct rtnl_link_info_ops *io = link->l_info_ops;
187a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
188a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if (io != NULL) {
189a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		io->io_refcnt--;
190a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		io->io_free(link);
191a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		link->l_info_ops = NULL;
192a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	}
193a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf}
194a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
19544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void link_free_data(struct nl_object *c)
19644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
19744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link = nl_object_priv(c);
19844d362409d5469aed47d19e7908d19bd194493aThomas Graf
19944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link) {
200a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		struct rtnl_link_info_ops *io;
201a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
202a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		if ((io = link->l_info_ops) != NULL)
203a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf			release_link_info(link);
204a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
20544d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_put(link->l_addr);
20644d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_put(link->l_bcast);
20744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
20844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
20944d362409d5469aed47d19e7908d19bd194493aThomas Graf
21044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int link_clone(struct nl_object *_dst, struct nl_object *_src)
21144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
21244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *dst = nl_object_priv(_dst);
21344d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *src = nl_object_priv(_src);
214a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	int err;
21544d362409d5469aed47d19e7908d19bd194493aThomas Graf
21644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (src->l_addr)
21744d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!(dst->l_addr = nl_addr_clone(src->l_addr)))
2188a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_NOMEM;
21944d362409d5469aed47d19e7908d19bd194493aThomas Graf
22044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (src->l_bcast)
22144d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!(dst->l_bcast = nl_addr_clone(src->l_bcast)))
2228a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_NOMEM;
22344d362409d5469aed47d19e7908d19bd194493aThomas Graf
224a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if (src->l_info_ops && src->l_info_ops->io_clone) {
225a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		err = src->l_info_ops->io_clone(dst, src);
226a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		if (err < 0)
2278a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return err;
228a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	}
229a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
23044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
23144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
23244d362409d5469aed47d19e7908d19bd194493aThomas Graf
23344d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nla_policy link_policy[IFLA_MAX+1] = {
23444d362409d5469aed47d19e7908d19bd194493aThomas Graf	[IFLA_IFNAME]	= { .type = NLA_STRING,
23544d362409d5469aed47d19e7908d19bd194493aThomas Graf			    .maxlen = IFNAMSIZ },
23644d362409d5469aed47d19e7908d19bd194493aThomas Graf	[IFLA_MTU]	= { .type = NLA_U32 },
23744d362409d5469aed47d19e7908d19bd194493aThomas Graf	[IFLA_TXQLEN]	= { .type = NLA_U32 },
23844d362409d5469aed47d19e7908d19bd194493aThomas Graf	[IFLA_LINK]	= { .type = NLA_U32 },
23944d362409d5469aed47d19e7908d19bd194493aThomas Graf	[IFLA_WEIGHT]	= { .type = NLA_U32 },
24044d362409d5469aed47d19e7908d19bd194493aThomas Graf	[IFLA_MASTER]	= { .type = NLA_U32 },
2413ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	[IFLA_OPERSTATE]= { .type = NLA_U8 },
2423ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	[IFLA_LINKMODE] = { .type = NLA_U8 },
243a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	[IFLA_LINKINFO]	= { .type = NLA_NESTED },
24444d362409d5469aed47d19e7908d19bd194493aThomas Graf	[IFLA_QDISC]	= { .type = NLA_STRING,
24544d362409d5469aed47d19e7908d19bd194493aThomas Graf			    .maxlen = IFQDISCSIZ },
24644d362409d5469aed47d19e7908d19bd194493aThomas Graf	[IFLA_STATS]	= { .minlen = sizeof(struct rtnl_link_stats) },
24744d362409d5469aed47d19e7908d19bd194493aThomas Graf	[IFLA_MAP]	= { .minlen = sizeof(struct rtnl_link_ifmap) },
24844d362409d5469aed47d19e7908d19bd194493aThomas Graf};
24944d362409d5469aed47d19e7908d19bd194493aThomas Graf
250a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Grafstatic struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
251a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	[IFLA_INFO_KIND]	= { .type = NLA_STRING },
252a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	[IFLA_INFO_DATA]	= { .type = NLA_NESTED },
253a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	[IFLA_INFO_XSTATS]	= { .type = NLA_NESTED },
254a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf};
255a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
25644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
2573040a1d6254465bed9e44e4d1bf279c2c50cd16aThomas Graf			   struct nlmsghdr *n, struct nl_parser_param *pp)
25844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
25944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link;
26044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct ifinfomsg *ifi;
26144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nlattr *tb[IFLA_MAX+1];
26244d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
26344d362409d5469aed47d19e7908d19bd194493aThomas Graf
26444d362409d5469aed47d19e7908d19bd194493aThomas Graf	link = rtnl_link_alloc();
26544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link == NULL) {
2668a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		err = -NLE_NOMEM;
26744d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto errout;
26844d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
26944d362409d5469aed47d19e7908d19bd194493aThomas Graf
27044d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_msgtype = n->nlmsg_type;
27144d362409d5469aed47d19e7908d19bd194493aThomas Graf
27244d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy);
27344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
27444d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto errout;
27544d362409d5469aed47d19e7908d19bd194493aThomas Graf
27644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[IFLA_IFNAME] == NULL) {
2778a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		err = -NLE_MISSING_ATTR;
27844d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto errout;
27944d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
28044d362409d5469aed47d19e7908d19bd194493aThomas Graf
28144d362409d5469aed47d19e7908d19bd194493aThomas Graf	nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
28244d362409d5469aed47d19e7908d19bd194493aThomas Graf
28344d362409d5469aed47d19e7908d19bd194493aThomas Graf	ifi = nlmsg_data(n);
28444d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_family = ifi->ifi_family;
28544d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_arptype = ifi->ifi_type;
28644d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_index = ifi->ifi_index;
28744d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_flags = ifi->ifi_flags;
28844d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_change = ifi->ifi_change;
28944d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
29044d362409d5469aed47d19e7908d19bd194493aThomas Graf			  LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
29144d362409d5469aed47d19e7908d19bd194493aThomas Graf			  LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
29244d362409d5469aed47d19e7908d19bd194493aThomas Graf
29344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[IFLA_STATS]) {
29444d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
29544d362409d5469aed47d19e7908d19bd194493aThomas Graf
29644d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_PACKETS]	= st->rx_packets;
29744d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_BYTES]	= st->rx_bytes;
29844d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_ERRORS]	= st->rx_errors;
29944d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_DROPPED]	= st->rx_dropped;
30044d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_COMPRESSED]	= st->rx_compressed;
30144d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_FIFO_ERR]	= st->rx_fifo_errors;
30244d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_PACKETS]	= st->tx_packets;
30344d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_BYTES]	= st->tx_bytes;
30444d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_ERRORS]	= st->tx_errors;
30544d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_DROPPED]	= st->tx_dropped;
30644d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_COMPRESSED]	= st->tx_compressed;
30744d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_FIFO_ERR]	= st->tx_fifo_errors;
30844d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_LEN_ERR]	= st->rx_length_errors;
30944d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_OVER_ERR]	= st->rx_over_errors;
31044d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_CRC_ERR]	= st->rx_crc_errors;
31144d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_FRAME_ERR]	= st->rx_frame_errors;
31244d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_MISSED_ERR]	= st->rx_missed_errors;
31344d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_ABORT_ERR]	= st->tx_aborted_errors;
31444d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_CARRIER_ERR]	= st->tx_carrier_errors;
31544d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_HBEAT_ERR]	= st->tx_heartbeat_errors;
31644d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_WIN_ERR]	= st->tx_window_errors;
31744d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_MULTICAST]	= st->multicast;
31844d362409d5469aed47d19e7908d19bd194493aThomas Graf
31944d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->ce_mask |= LINK_ATTR_STATS;
32044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
32144d362409d5469aed47d19e7908d19bd194493aThomas Graf
32244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[IFLA_TXQLEN]) {
32344d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]);
32444d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->ce_mask |= LINK_ATTR_TXQLEN;
32544d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
32644d362409d5469aed47d19e7908d19bd194493aThomas Graf
32744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[IFLA_MTU]) {
32844d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_mtu = nla_get_u32(tb[IFLA_MTU]);
32944d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->ce_mask |= LINK_ATTR_MTU;
33044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
33144d362409d5469aed47d19e7908d19bd194493aThomas Graf
33244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[IFLA_ADDRESS]) {
333eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC);
334eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		if (link->l_addr == NULL) {
335eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			err = -NLE_NOMEM;
33644d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
337eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		}
33844d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_set_family(link->l_addr,
33944d362409d5469aed47d19e7908d19bd194493aThomas Graf				   nl_addr_guess_family(link->l_addr));
34044d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->ce_mask |= LINK_ATTR_ADDR;
34144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
34244d362409d5469aed47d19e7908d19bd194493aThomas Graf
34344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[IFLA_BROADCAST]) {
344eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		link->l_bcast = nl_addr_alloc_attr(tb[IFLA_BROADCAST],
345eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf						   AF_UNSPEC);
346eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		if (link->l_bcast == NULL) {
347eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			err = -NLE_NOMEM;
34844d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
349eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		}
35044d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_set_family(link->l_bcast,
35144d362409d5469aed47d19e7908d19bd194493aThomas Graf				   nl_addr_guess_family(link->l_bcast));
35244d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->ce_mask |= LINK_ATTR_BRD;
35344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
35444d362409d5469aed47d19e7908d19bd194493aThomas Graf
35544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[IFLA_LINK]) {
35644d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_link = nla_get_u32(tb[IFLA_LINK]);
35744d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->ce_mask |= LINK_ATTR_LINK;
35844d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
35944d362409d5469aed47d19e7908d19bd194493aThomas Graf
36044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[IFLA_WEIGHT]) {
36144d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]);
36244d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->ce_mask |= LINK_ATTR_WEIGHT;
36344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
36444d362409d5469aed47d19e7908d19bd194493aThomas Graf
36544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[IFLA_QDISC]) {
36644d362409d5469aed47d19e7908d19bd194493aThomas Graf		nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
36744d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->ce_mask |= LINK_ATTR_QDISC;
36844d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
36944d362409d5469aed47d19e7908d19bd194493aThomas Graf
37044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[IFLA_MAP]) {
3710ca291d9e4ca1a9fd75982e7edb43325b40f5f10Thomas Graf		nla_memcpy(&link->l_map, tb[IFLA_MAP],
3720ca291d9e4ca1a9fd75982e7edb43325b40f5f10Thomas Graf			   sizeof(struct rtnl_link_ifmap));
37344d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->ce_mask |= LINK_ATTR_MAP;
37444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
37544d362409d5469aed47d19e7908d19bd194493aThomas Graf
37644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[IFLA_MASTER]) {
37744d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_master = nla_get_u32(tb[IFLA_MASTER]);
37844d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->ce_mask |= LINK_ATTR_MASTER;
37944d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
38044d362409d5469aed47d19e7908d19bd194493aThomas Graf
3813ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	if (tb[IFLA_OPERSTATE]) {
3823ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]);
3833ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		link->ce_mask |= LINK_ATTR_OPERSTATE;
3843ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	}
3853ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
3863ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	if (tb[IFLA_LINKMODE]) {
3873ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]);
3883ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		link->ce_mask |= LINK_ATTR_LINKMODE;
3893ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	}
3903ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
391a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if (tb[IFLA_LINKINFO]) {
392a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		struct nlattr *li[IFLA_INFO_MAX+1];
393a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
394a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
395a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf				       link_info_policy);
396a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		if (err < 0)
397a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf			goto errout;
398a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
399a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		if (li[IFLA_INFO_KIND] &&
400a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		    (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
401a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf			struct rtnl_link_info_ops *ops;
402a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf			char *kind;
403a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
404a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf			kind = nla_get_string(li[IFLA_INFO_KIND]);
405a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf			ops = rtnl_link_info_ops_lookup(kind);
406a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf			if (ops != NULL) {
407a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf				ops->io_refcnt++;
408a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf				link->l_info_ops = ops;
409a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf				err = ops->io_parse(link, li[IFLA_INFO_DATA],
410a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf						    li[IFLA_INFO_XSTATS]);
411a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf				if (err < 0)
412a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf					goto errout;
413a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf			} else {
414a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf				/* XXX: Warn about unparsed info? */
415a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf			}
416a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		}
417a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	}
418a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
41944d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = pp->pp_cb((struct nl_object *) link, pp);
42044d362409d5469aed47d19e7908d19bd194493aThomas Graferrout:
42144d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_link_put(link);
42244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return err;
42344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
42444d362409d5469aed47d19e7908d19bd194493aThomas Graf
4251155370f520cb64657e25153255cf7dc1424317fThomas Grafstatic int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
42644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
4271155370f520cb64657e25153255cf7dc1424317fThomas Graf	return nl_rtgen_request(sk, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
42844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
42944d362409d5469aed47d19e7908d19bd194493aThomas Graf
430d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
43144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
43244d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[128];
43344d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cache *cache = dp_cache(obj);
43444d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link = (struct rtnl_link *) obj;
43544d362409d5469aed47d19e7908d19bd194493aThomas Graf
436d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "%s %s ", link->l_name,
437d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		     nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
4383ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
4393ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	if (link->l_addr && !nl_addr_iszero(link->l_addr))
440d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
44144d362409d5469aed47d19e7908d19bd194493aThomas Graf
44244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_MASTER) {
44344d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
444d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "master %s ", master ? master->l_name : "inv");
44544d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (master)
44644d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_link_put(master);
44744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
44844d362409d5469aed47d19e7908d19bd194493aThomas Graf
44944d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
45044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (buf[0])
451d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "<%s> ", buf);
452a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
453a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if (link->ce_mask & LINK_ATTR_LINK) {
454a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
455d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
456a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		if (ll)
457a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf			rtnl_link_put(ll);
458a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	}
459a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
460d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE])
461d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		link->l_info_ops->io_dump[NL_DUMP_LINE](link, p);
46244d362409d5469aed47d19e7908d19bd194493aThomas Graf
463d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump(p, "\n");
46444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
46544d362409d5469aed47d19e7908d19bd194493aThomas Graf
466d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void link_dump_details(struct nl_object *obj, struct nl_dump_params *p)
46744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
46844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link = (struct rtnl_link *) obj;
46944d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[64];
47044d362409d5469aed47d19e7908d19bd194493aThomas Graf
471d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	link_dump_line(obj, p);
47244d362409d5469aed47d19e7908d19bd194493aThomas Graf
473d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "    mtu %u ", link->l_mtu);
474d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
47544d362409d5469aed47d19e7908d19bd194493aThomas Graf
47644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_QDISC)
477d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "qdisc %s ", link->l_qdisc);
47844d362409d5469aed47d19e7908d19bd194493aThomas Graf
47944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
480d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "irq %u ", link->l_map.lm_irq);
48144d362409d5469aed47d19e7908d19bd194493aThomas Graf
48244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_IFINDEX)
483d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "index %u ", link->l_index);
48444d362409d5469aed47d19e7908d19bd194493aThomas Graf
4853ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
486d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump(p, "\n");
487d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "    ");
4883ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
48944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_BRD)
490d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
49144d362409d5469aed47d19e7908d19bd194493aThomas Graf						   sizeof(buf)));
49244d362409d5469aed47d19e7908d19bd194493aThomas Graf
4933ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
4943ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	    link->l_operstate != IF_OPER_UNKNOWN) {
4953ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
496d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "state %s ", buf);
4973ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	}
4983ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
499d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump(p, "mode %s\n",
5003ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
50144d362409d5469aed47d19e7908d19bd194493aThomas Graf
502d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS])
503d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p);
50444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
50544d362409d5469aed47d19e7908d19bd194493aThomas Graf
506d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
50744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
50844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link = (struct rtnl_link *) obj;
50944d362409d5469aed47d19e7908d19bd194493aThomas Graf	char *unit, fmt[64];
51044d362409d5469aed47d19e7908d19bd194493aThomas Graf	float res;
51144d362409d5469aed47d19e7908d19bd194493aThomas Graf
512d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	link_dump_details(obj, p);
51344d362409d5469aed47d19e7908d19bd194493aThomas Graf
514d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "    Stats:    bytes    packets     errors "
515d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf			"   dropped   fifo-err compressed\n");
51644d362409d5469aed47d19e7908d19bd194493aThomas Graf
51744d362409d5469aed47d19e7908d19bd194493aThomas Graf	res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
51844d362409d5469aed47d19e7908d19bd194493aThomas Graf
5197f6b7a8eea0334b34d58dec72c66121a76f08958Thomas Graf	strcpy(fmt, "     RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
52044d362409d5469aed47d19e7908d19bd194493aThomas Graf	fmt[9] = *unit == 'B' ? '9' : '7';
52144d362409d5469aed47d19e7908d19bd194493aThomas Graf
522d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, fmt, res, unit,
52344d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_PACKETS],
52444d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_ERRORS],
52544d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_DROPPED],
52644d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_FIFO_ERR],
52744d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_COMPRESSED]);
52844d362409d5469aed47d19e7908d19bd194493aThomas Graf
52944d362409d5469aed47d19e7908d19bd194493aThomas Graf	res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
53044d362409d5469aed47d19e7908d19bd194493aThomas Graf
5317f6b7a8eea0334b34d58dec72c66121a76f08958Thomas Graf	strcpy(fmt, "     TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
53244d362409d5469aed47d19e7908d19bd194493aThomas Graf	fmt[9] = *unit == 'B' ? '9' : '7';
53344d362409d5469aed47d19e7908d19bd194493aThomas Graf
534d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, fmt, res, unit,
53544d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_PACKETS],
53644d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_ERRORS],
53744d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_DROPPED],
53844d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_FIFO_ERR],
53944d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_COMPRESSED]);
54044d362409d5469aed47d19e7908d19bd194493aThomas Graf
541d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "    Errors:  length       over        crc "
542d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf			"     frame     missed  multicast\n");
54344d362409d5469aed47d19e7908d19bd194493aThomas Graf
544d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "     RX  %10" PRIu64 " %10" PRIu64 " %10"
54544d362409d5469aed47d19e7908d19bd194493aThomas Graf				PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
54644d362409d5469aed47d19e7908d19bd194493aThomas Graf				PRIu64 "\n",
54744d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_LEN_ERR],
54844d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_OVER_ERR],
54944d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_CRC_ERR],
55044d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_FRAME_ERR],
55144d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_MISSED_ERR],
55244d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_MULTICAST]);
55344d362409d5469aed47d19e7908d19bd194493aThomas Graf
554d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "            aborted    carrier  heartbeat "
555d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf			"    window  collision\n");
55644d362409d5469aed47d19e7908d19bd194493aThomas Graf
557d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "     TX  %10" PRIu64 " %10" PRIu64 " %10"
558d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf			PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
55944d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_ABORT_ERR],
56044d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
56144d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
56244d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_WIN_ERR],
56344d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_COLLISIONS]);
56444d362409d5469aed47d19e7908d19bd194493aThomas Graf
565a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
566d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		link->l_info_ops->io_dump[NL_DUMP_STATS](link, p);
56744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
56844d362409d5469aed47d19e7908d19bd194493aThomas Graf
569d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void link_dump_env(struct nl_object *obj, struct nl_dump_params *p)
57044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
57144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link = (struct rtnl_link *) obj;
57244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cache *cache = dp_cache(obj);
57344d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[128];
574d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	int i;
57544d362409d5469aed47d19e7908d19bd194493aThomas Graf
576d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "LINK_NAME=%s\n", link->l_name);
577d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "LINK_IFINDEX=%u\n", link->l_index);
578d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "LINK_FAMILY=%s\n",
57944d362409d5469aed47d19e7908d19bd194493aThomas Graf		     nl_af2str(link->l_family, buf, sizeof(buf)));
580d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "LINK_TYPE=%s\n",
58144d362409d5469aed47d19e7908d19bd194493aThomas Graf		     nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
58244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_ADDR)
583d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump_line(p, "LINK_ADDRESS=%s\n",
58444d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(link->l_addr, buf, sizeof(buf)));
585d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "LINK_MTU=%u\n", link->l_mtu);
586d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "LINK_TXQUEUELEN=%u\n", link->l_txqlen);
587d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "LINK_WEIGHT=%u\n", link->l_weight);
58844d362409d5469aed47d19e7908d19bd194493aThomas Graf
58944d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_link_flags2str(link->l_flags & ~IFF_RUNNING, buf, sizeof(buf));
59044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (buf[0])
591d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump_line(p, "LINK_FLAGS=%s\n", buf);
59244d362409d5469aed47d19e7908d19bd194493aThomas Graf
59344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_QDISC)
594d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump_line(p, "LINK_QDISC=%s\n", link->l_qdisc);
59544d362409d5469aed47d19e7908d19bd194493aThomas Graf
59644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_LINK) {
59744d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
59844d362409d5469aed47d19e7908d19bd194493aThomas Graf
599d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump_line(p, "LINK_LINK_IFINDEX=%d\n", link->l_link);
60044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (ll) {
601d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf			nl_dump_line(p, "LINK_LINK_IFNAME=%s\n", ll->l_name);
60244d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_link_put(ll);
60344d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
60444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
60544d362409d5469aed47d19e7908d19bd194493aThomas Graf
60644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_MASTER) {
60744d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
608d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump_line(p, "LINK_MASTER=%s\n",
60944d362409d5469aed47d19e7908d19bd194493aThomas Graf			     master ? master->l_name : "none");
61044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (master)
61144d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_link_put(master);
61244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
61344d362409d5469aed47d19e7908d19bd194493aThomas Graf
61444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_BRD)
615d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump_line(p, "LINK_BROADCAST=%s\n",
61644d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(link->l_bcast, buf, sizeof(buf)));
61744d362409d5469aed47d19e7908d19bd194493aThomas Graf
61844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_STATS) {
61944d362409d5469aed47d19e7908d19bd194493aThomas Graf		for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
62044d362409d5469aed47d19e7908d19bd194493aThomas Graf			char *c = buf;
62144d362409d5469aed47d19e7908d19bd194493aThomas Graf
62244d362409d5469aed47d19e7908d19bd194493aThomas Graf			sprintf(buf, "LINK_");
62344d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_link_stat2str(i, buf + 5, sizeof(buf) - 5);
62444d362409d5469aed47d19e7908d19bd194493aThomas Graf			while (*c) {
62544d362409d5469aed47d19e7908d19bd194493aThomas Graf				*c = toupper(*c);
62644d362409d5469aed47d19e7908d19bd194493aThomas Graf				c++;
62744d362409d5469aed47d19e7908d19bd194493aThomas Graf			}
628d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf			nl_dump_line(p, "%s=%" PRIu64 "\n", buf, link->l_stats[i]);
62944d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
63044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
63144d362409d5469aed47d19e7908d19bd194493aThomas Graf
632a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_ENV])
633d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		link->l_info_ops->io_dump[NL_DUMP_ENV](link, p);
63444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
63544d362409d5469aed47d19e7908d19bd194493aThomas Graf
63644d362409d5469aed47d19e7908d19bd194493aThomas Graf#if 0
63744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
63844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
63944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *l = (struct rtnl_link *) a;
64044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cache *c = dp_cache(a);
64144d362409d5469aed47d19e7908d19bd194493aThomas Graf	int nevents = 0;
64244d362409d5469aed47d19e7908d19bd194493aThomas Graf
64344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (l->l_change == ~0U) {
64444d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (l->ce_msgtype == RTM_NEWLINK)
64544d362409d5469aed47d19e7908d19bd194493aThomas Graf			cb->le_register(l);
64644d362409d5469aed47d19e7908d19bd194493aThomas Graf		else
64744d362409d5469aed47d19e7908d19bd194493aThomas Graf			cb->le_unregister(l);
64844d362409d5469aed47d19e7908d19bd194493aThomas Graf
64944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 1;
65044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
65144d362409d5469aed47d19e7908d19bd194493aThomas Graf
65244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (l->l_change & IFF_SLAVE) {
65344d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (l->l_flags & IFF_SLAVE) {
65444d362409d5469aed47d19e7908d19bd194493aThomas Graf			struct rtnl_link *m = rtnl_link_get(c, l->l_master);
65544d362409d5469aed47d19e7908d19bd194493aThomas Graf			cb->le_new_bonding(l, m);
65644d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (m)
65744d362409d5469aed47d19e7908d19bd194493aThomas Graf				rtnl_link_put(m);
65844d362409d5469aed47d19e7908d19bd194493aThomas Graf		} else
65944d362409d5469aed47d19e7908d19bd194493aThomas Graf			cb->le_cancel_bonding(l);
66044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
66144d362409d5469aed47d19e7908d19bd194493aThomas Graf
66244d362409d5469aed47d19e7908d19bd194493aThomas Graf#if 0
66344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
66444d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "link %s changed state to %s.\n",
66544d362409d5469aed47d19e7908d19bd194493aThomas Graf			l->l_name, l->l_flags & IFF_UP ? "up" : "down");
66644d362409d5469aed47d19e7908d19bd194493aThomas Graf
66744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (l->l_change & IFF_PROMISC) {
66844d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_new_line(p, line++);
66944d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "link %s %s promiscuous mode.\n",
67044d362409d5469aed47d19e7908d19bd194493aThomas Graf		    l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
67144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
67244d362409d5469aed47d19e7908d19bd194493aThomas Graf
67344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (line == 0)
67444d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "link %s sent unknown event.\n",
67544d362409d5469aed47d19e7908d19bd194493aThomas Graf			     l->l_name);
67644d362409d5469aed47d19e7908d19bd194493aThomas Graf#endif
67744d362409d5469aed47d19e7908d19bd194493aThomas Graf
67844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return nevents;
67944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
68044d362409d5469aed47d19e7908d19bd194493aThomas Graf#endif
68144d362409d5469aed47d19e7908d19bd194493aThomas Graf
68244d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int link_compare(struct nl_object *_a, struct nl_object *_b,
68344d362409d5469aed47d19e7908d19bd194493aThomas Graf			uint32_t attrs, int flags)
68444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
68544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *a = (struct rtnl_link *) _a;
68644d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *b = (struct rtnl_link *) _b;
68744d362409d5469aed47d19e7908d19bd194493aThomas Graf	int diff = 0;
68844d362409d5469aed47d19e7908d19bd194493aThomas Graf
68944d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
69044d362409d5469aed47d19e7908d19bd194493aThomas Graf
69144d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(IFINDEX,	a->l_index != b->l_index);
69244d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(MTU,		a->l_mtu != b->l_mtu);
69344d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(LINK,		a->l_link != b->l_link);
69444d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(TXQLEN,	a->l_txqlen != b->l_txqlen);
69544d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(WEIGHT,	a->l_weight != b->l_weight);
69644d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(MASTER,	a->l_master != b->l_master);
69744d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(FAMILY,	a->l_family != b->l_family);
6983ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	diff |= LINK_DIFF(OPERSTATE,	a->l_operstate != b->l_operstate);
6993ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	diff |= LINK_DIFF(LINKMODE,	a->l_linkmode != b->l_linkmode);
70044d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(QDISC,	strcmp(a->l_qdisc, b->l_qdisc));
70144d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(IFNAME,	strcmp(a->l_name, b->l_name));
70244d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(ADDR,		nl_addr_cmp(a->l_addr, b->l_addr));
70344d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(BRD,		nl_addr_cmp(a->l_bcast, b->l_bcast));
70444d362409d5469aed47d19e7908d19bd194493aThomas Graf
705535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (flags & LOOSE_COMPARISON)
70644d362409d5469aed47d19e7908d19bd194493aThomas Graf		diff |= LINK_DIFF(FLAGS,
70744d362409d5469aed47d19e7908d19bd194493aThomas Graf				  (a->l_flags ^ b->l_flags) & b->l_flag_mask);
70844d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
70944d362409d5469aed47d19e7908d19bd194493aThomas Graf		diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
71044d362409d5469aed47d19e7908d19bd194493aThomas Graf
71144d362409d5469aed47d19e7908d19bd194493aThomas Graf#undef LINK_DIFF
71244d362409d5469aed47d19e7908d19bd194493aThomas Graf
71344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return diff;
71444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
71544d362409d5469aed47d19e7908d19bd194493aThomas Graf
71644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct trans_tbl link_attrs[] = {
71744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_MTU, mtu)
71844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_LINK, link)
71944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_TXQLEN, txqlen)
72044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_WEIGHT, weight)
72144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_MASTER, master)
72244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_QDISC, qdisc)
72344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_MAP, map)
72444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_ADDR, address)
72544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_BRD, broadcast)
72644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_FLAGS, flags)
72744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_IFNAME, name)
72844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_IFINDEX, ifindex)
72944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_FAMILY, family)
73044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_ARPTYPE, arptype)
73144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_STATS, stats)
73244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_CHANGE, change)
7333ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(LINK_ATTR_OPERSTATE, operstate)
7343ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(LINK_ATTR_LINKMODE, linkmode)
73544d362409d5469aed47d19e7908d19bd194493aThomas Graf};
73644d362409d5469aed47d19e7908d19bd194493aThomas Graf
73744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic char *link_attrs2str(int attrs, char *buf, size_t len)
73844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
73944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __flags2str(attrs, buf, len, link_attrs,
74044d362409d5469aed47d19e7908d19bd194493aThomas Graf			   ARRAY_SIZE(link_attrs));
74144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
74244d362409d5469aed47d19e7908d19bd194493aThomas Graf
74344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
74444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Allocation/Freeing
74544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
74644d362409d5469aed47d19e7908d19bd194493aThomas Graf */
74744d362409d5469aed47d19e7908d19bd194493aThomas Graf
74844d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct rtnl_link *rtnl_link_alloc(void)
74944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
75044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
75144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
75244d362409d5469aed47d19e7908d19bd194493aThomas Graf
75344d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_put(struct rtnl_link *link)
75444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
75544d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_object_put((struct nl_object *) link);
75644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
75744d362409d5469aed47d19e7908d19bd194493aThomas Graf
75844d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
75944d362409d5469aed47d19e7908d19bd194493aThomas Graf
76044d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
76144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Cache Management
76244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
76344d362409d5469aed47d19e7908d19bd194493aThomas Graf */
76444d362409d5469aed47d19e7908d19bd194493aThomas Graf
76544d362409d5469aed47d19e7908d19bd194493aThomas Graf
76644d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
76744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Allocate link cache and fill in all configured links.
7681155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
7698a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * @arg result		Pointer to store resulting cache.
77044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
77144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Allocates a new link cache, initializes it properly and updates it
77244d362409d5469aed47d19e7908d19bd194493aThomas Graf * to include all links currently configured in the kernel.
77344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
7748a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * @return 0 on success or a negative error code.
77544d362409d5469aed47d19e7908d19bd194493aThomas Graf */
7761155370f520cb64657e25153255cf7dc1424317fThomas Grafint rtnl_link_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
77744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
7781155370f520cb64657e25153255cf7dc1424317fThomas Graf	return nl_cache_alloc_and_fill(&rtnl_link_ops, sk, result);
77944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
78044d362409d5469aed47d19e7908d19bd194493aThomas Graf
78144d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
78244d362409d5469aed47d19e7908d19bd194493aThomas Graf * Look up link by interface index in the provided cache
78344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cache		link cache
78444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg ifindex		link interface index
78544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
78644d362409d5469aed47d19e7908d19bd194493aThomas Graf * The caller owns a reference on the returned object and
78744d362409d5469aed47d19e7908d19bd194493aThomas Graf * must give the object back via rtnl_link_put().
78844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
78944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return pointer to link inside the cache or NULL if no match was found.
79044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
79144d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
79244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
79344d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link;
79444d362409d5469aed47d19e7908d19bd194493aThomas Graf
79544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (cache->c_ops != &rtnl_link_ops)
79644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
79744d362409d5469aed47d19e7908d19bd194493aThomas Graf
79844d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_list_for_each_entry(link, &cache->c_items, ce_list) {
79944d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (link->l_index == ifindex) {
80044d362409d5469aed47d19e7908d19bd194493aThomas Graf			nl_object_get((struct nl_object *) link);
80144d362409d5469aed47d19e7908d19bd194493aThomas Graf			return link;
80244d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
80344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
80444d362409d5469aed47d19e7908d19bd194493aThomas Graf
80544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NULL;
80644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
80744d362409d5469aed47d19e7908d19bd194493aThomas Graf
80844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
80944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Look up link by link name in the provided cache
81044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cache		link cache
81144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg name		link name
81244d362409d5469aed47d19e7908d19bd194493aThomas Graf *
81344d362409d5469aed47d19e7908d19bd194493aThomas Graf * The caller owns a reference on the returned object and
81444d362409d5469aed47d19e7908d19bd194493aThomas Graf * must give the object back via rtnl_link_put().
81544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
81644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return pointer to link inside the cache or NULL if no match was found.
81744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
81844d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
81944d362409d5469aed47d19e7908d19bd194493aThomas Graf					 const char *name)
82044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
82144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link;
82244d362409d5469aed47d19e7908d19bd194493aThomas Graf
82344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (cache->c_ops != &rtnl_link_ops)
82444d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
82544d362409d5469aed47d19e7908d19bd194493aThomas Graf
82644d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_list_for_each_entry(link, &cache->c_items, ce_list) {
82744d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!strcmp(name, link->l_name)) {
82844d362409d5469aed47d19e7908d19bd194493aThomas Graf			nl_object_get((struct nl_object *) link);
82944d362409d5469aed47d19e7908d19bd194493aThomas Graf			return link;
83044d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
83144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
83244d362409d5469aed47d19e7908d19bd194493aThomas Graf
83344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NULL;
83444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
83544d362409d5469aed47d19e7908d19bd194493aThomas Graf
83644d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
83744d362409d5469aed47d19e7908d19bd194493aThomas Graf
83844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
83944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Link Modifications
84044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
84144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
84244d362409d5469aed47d19e7908d19bd194493aThomas Graf
84344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
84444d362409d5469aed47d19e7908d19bd194493aThomas Graf * Builds a netlink change request message to change link attributes
84544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg old		link to be changed
84644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg tmpl		template with requested changes
84744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg flags		additional netlink message flags
84844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
84944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Builds a new netlink message requesting a change of link attributes.
85044d362409d5469aed47d19e7908d19bd194493aThomas Graf * The netlink message header isn't fully equipped with all relevant
85144d362409d5469aed47d19e7908d19bd194493aThomas Graf * fields and must be sent out via nl_send_auto_complete() or
85244d362409d5469aed47d19e7908d19bd194493aThomas Graf * supplemented as needed.
85344d362409d5469aed47d19e7908d19bd194493aThomas Graf * \a old must point to a link currently configured in the kernel
85444d362409d5469aed47d19e7908d19bd194493aThomas Graf * and \a tmpl must contain the attributes to be changed set via
85544d362409d5469aed47d19e7908d19bd194493aThomas Graf * \c rtnl_link_set_* functions.
85644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
85744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return New netlink message
85844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @note Not all attributes can be changed, see
85944d362409d5469aed47d19e7908d19bd194493aThomas Graf *       \ref link_changeable "Changeable Attributes" for more details.
86044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
8618a3efffa5b3fde252675239914118664d36a2c24Thomas Grafint rtnl_link_build_change_request(struct rtnl_link *old,
8628a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				   struct rtnl_link *tmpl, int flags,
8638a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				   struct nl_msg **result)
86444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
86544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_msg *msg;
86644d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct ifinfomsg ifi = {
86744d362409d5469aed47d19e7908d19bd194493aThomas Graf		.ifi_family = old->l_family,
86844d362409d5469aed47d19e7908d19bd194493aThomas Graf		.ifi_index = old->l_index,
86944d362409d5469aed47d19e7908d19bd194493aThomas Graf	};
87044d362409d5469aed47d19e7908d19bd194493aThomas Graf
87144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tmpl->ce_mask & LINK_ATTR_FLAGS) {
87244d362409d5469aed47d19e7908d19bd194493aThomas Graf		ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask;
87344d362409d5469aed47d19e7908d19bd194493aThomas Graf		ifi.ifi_flags |= tmpl->l_flags;
87444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
87544d362409d5469aed47d19e7908d19bd194493aThomas Graf
87644d362409d5469aed47d19e7908d19bd194493aThomas Graf	msg = nlmsg_alloc_simple(RTM_SETLINK, flags);
87744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!msg)
8788a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
87944d362409d5469aed47d19e7908d19bd194493aThomas Graf
88044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
88144d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto nla_put_failure;
88244d362409d5469aed47d19e7908d19bd194493aThomas Graf
88344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tmpl->ce_mask & LINK_ATTR_ADDR)
88444d362409d5469aed47d19e7908d19bd194493aThomas Graf		NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr);
88544d362409d5469aed47d19e7908d19bd194493aThomas Graf
88644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tmpl->ce_mask & LINK_ATTR_BRD)
88744d362409d5469aed47d19e7908d19bd194493aThomas Graf		NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast);
88844d362409d5469aed47d19e7908d19bd194493aThomas Graf
88944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tmpl->ce_mask & LINK_ATTR_MTU)
89044d362409d5469aed47d19e7908d19bd194493aThomas Graf		NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu);
89144d362409d5469aed47d19e7908d19bd194493aThomas Graf
89244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tmpl->ce_mask & LINK_ATTR_TXQLEN)
89344d362409d5469aed47d19e7908d19bd194493aThomas Graf		NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen);
89444d362409d5469aed47d19e7908d19bd194493aThomas Graf
89544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tmpl->ce_mask & LINK_ATTR_WEIGHT)
89644d362409d5469aed47d19e7908d19bd194493aThomas Graf		NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight);
89744d362409d5469aed47d19e7908d19bd194493aThomas Graf
89844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tmpl->ce_mask & LINK_ATTR_IFNAME)
89944d362409d5469aed47d19e7908d19bd194493aThomas Graf		NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name);
90044d362409d5469aed47d19e7908d19bd194493aThomas Graf
9013ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	if (tmpl->ce_mask & LINK_ATTR_OPERSTATE)
9023ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		NLA_PUT_U8(msg, IFLA_OPERSTATE, tmpl->l_operstate);
9033ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
9043ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	if (tmpl->ce_mask & LINK_ATTR_LINKMODE)
9053ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		NLA_PUT_U8(msg, IFLA_LINKMODE, tmpl->l_linkmode);
9063ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
907a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if ((tmpl->ce_mask & LINK_ATTR_LINKINFO) && tmpl->l_info_ops &&
908a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	    tmpl->l_info_ops->io_put_attrs) {
909a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		struct nlattr *info;
910a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
911a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
912a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf			goto nla_put_failure;
913a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
914a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		NLA_PUT_STRING(msg, IFLA_INFO_KIND, tmpl->l_info_ops->io_name);
915a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
916a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		if (tmpl->l_info_ops->io_put_attrs(msg, tmpl) < 0)
917a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf			goto nla_put_failure;
918a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
919a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		nla_nest_end(msg, info);
920a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	}
921a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
9228a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	*result = msg;
9238a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return 0;
92444d362409d5469aed47d19e7908d19bd194493aThomas Graf
92544d362409d5469aed47d19e7908d19bd194493aThomas Grafnla_put_failure:
92644d362409d5469aed47d19e7908d19bd194493aThomas Graf	nlmsg_free(msg);
9278a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return -NLE_MSGSIZE;
92844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
92944d362409d5469aed47d19e7908d19bd194493aThomas Graf
93044d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
93144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Change link attributes
9321155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
93344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg old		link to be changed
93444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg tmpl		template with requested changes
93544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg flags		additional netlink message flags
93644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
93744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Builds a new netlink message by calling rtnl_link_build_change_request(),
93844d362409d5469aed47d19e7908d19bd194493aThomas Graf * sends the request to the kernel and waits for the next ACK to be
93944d362409d5469aed47d19e7908d19bd194493aThomas Graf * received, i.e. blocks until the request has been processed.
94044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
94144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code
94244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @note Not all attributes can be changed, see
94344d362409d5469aed47d19e7908d19bd194493aThomas Graf *       \ref link_changeable "Changeable Attributes" for more details.
94444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
9451155370f520cb64657e25153255cf7dc1424317fThomas Grafint rtnl_link_change(struct nl_sock *sk, struct rtnl_link *old,
94644d362409d5469aed47d19e7908d19bd194493aThomas Graf		     struct rtnl_link *tmpl, int flags)
94744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
94844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_msg *msg;
9498a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	int err;
95044d362409d5469aed47d19e7908d19bd194493aThomas Graf
9518a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	if ((err = rtnl_link_build_change_request(old, tmpl, flags, &msg)) < 0)
9528a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return err;
95344d362409d5469aed47d19e7908d19bd194493aThomas Graf
954ef50a38fbd8682a5c9efd559e7db68664977f080Thomas Graf	err = nl_send_auto_complete(sk, msg);
955ef50a38fbd8682a5c9efd559e7db68664977f080Thomas Graf	nlmsg_free(msg);
956ef50a38fbd8682a5c9efd559e7db68664977f080Thomas Graf	if (err < 0)
95744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
95844d362409d5469aed47d19e7908d19bd194493aThomas Graf
959cfcfca070355b246028df60da79813f09ed65755Thomas Graf	return wait_for_ack(sk);
96044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
96144d362409d5469aed47d19e7908d19bd194493aThomas Graf
96244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
96344d362409d5469aed47d19e7908d19bd194493aThomas Graf
96444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
96544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Name <-> Index Translations
96644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
96744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
96844d362409d5469aed47d19e7908d19bd194493aThomas Graf
96944d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
97044d362409d5469aed47d19e7908d19bd194493aThomas Graf * Translate an interface index to the corresponding link name
97144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cache		link cache
97244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg ifindex		link interface index
97344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg dst		destination buffer
97444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg len		length of destination buffer
97544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
97644d362409d5469aed47d19e7908d19bd194493aThomas Graf * Translates the specified interface index to the corresponding
97744d362409d5469aed47d19e7908d19bd194493aThomas Graf * link name and stores the name in the destination buffer.
97844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
97944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return link name or NULL if no match was found.
98044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
98144d362409d5469aed47d19e7908d19bd194493aThomas Grafchar * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
98244d362409d5469aed47d19e7908d19bd194493aThomas Graf			size_t len)
98344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
98444d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link = rtnl_link_get(cache, ifindex);
98544d362409d5469aed47d19e7908d19bd194493aThomas Graf
98644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link) {
98744d362409d5469aed47d19e7908d19bd194493aThomas Graf		strncpy(dst, link->l_name, len - 1);
98844d362409d5469aed47d19e7908d19bd194493aThomas Graf		rtnl_link_put(link);
98944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return dst;
99044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
99144d362409d5469aed47d19e7908d19bd194493aThomas Graf
99244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NULL;
99344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
99444d362409d5469aed47d19e7908d19bd194493aThomas Graf
99544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
99644d362409d5469aed47d19e7908d19bd194493aThomas Graf * Translate a link name to the corresponding interface index
99744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cache		link cache
99844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg name		link name
99944d362409d5469aed47d19e7908d19bd194493aThomas Graf *
1000b4fbe1d34d6f54045b5c6236d86aacd4340ec83dThomas Graf * @return interface index or 0 if no match was found.
100144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
100244d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_link_name2i(struct nl_cache *cache, const char *name)
100344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
1004b4fbe1d34d6f54045b5c6236d86aacd4340ec83dThomas Graf	int ifindex = 0;
100544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link;
100644d362409d5469aed47d19e7908d19bd194493aThomas Graf
100744d362409d5469aed47d19e7908d19bd194493aThomas Graf	link = rtnl_link_get_by_name(cache, name);
100844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link) {
100944d362409d5469aed47d19e7908d19bd194493aThomas Graf		ifindex = link->l_index;
101044d362409d5469aed47d19e7908d19bd194493aThomas Graf		rtnl_link_put(link);
101144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
101244d362409d5469aed47d19e7908d19bd194493aThomas Graf
101344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return ifindex;
101444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
101544d362409d5469aed47d19e7908d19bd194493aThomas Graf
101644d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
101744d362409d5469aed47d19e7908d19bd194493aThomas Graf
101844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
101944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Link Flags Translations
102044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
102144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
102244d362409d5469aed47d19e7908d19bd194493aThomas Graf
102344d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct trans_tbl link_flags[] = {
102444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_LOOPBACK, loopback)
102544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_BROADCAST, broadcast)
102644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_POINTOPOINT, pointopoint)
102744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_MULTICAST, multicast)
102844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_NOARP, noarp)
102944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_ALLMULTI, allmulti)
103044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_PROMISC, promisc)
103144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_MASTER, master)
103244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_SLAVE, slave)
103344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_DEBUG, debug)
103444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_DYNAMIC, dynamic)
103544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_AUTOMEDIA, automedia)
103644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_PORTSEL, portsel)
103744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_NOTRAILERS, notrailers)
103844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_UP, up)
103944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_RUNNING, running)
104044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_LOWER_UP, lowerup)
104144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_DORMANT, dormant)
1042195241473723527e2f30ac120087f106c607ce3eThomas Graf	__ADD(IFF_ECHO, echo)
104344d362409d5469aed47d19e7908d19bd194493aThomas Graf};
104444d362409d5469aed47d19e7908d19bd194493aThomas Graf
104544d362409d5469aed47d19e7908d19bd194493aThomas Grafchar * rtnl_link_flags2str(int flags, char *buf, size_t len)
104644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
104744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __flags2str(flags, buf, len, link_flags,
104844d362409d5469aed47d19e7908d19bd194493aThomas Graf			   ARRAY_SIZE(link_flags));
104944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
105044d362409d5469aed47d19e7908d19bd194493aThomas Graf
105144d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_link_str2flags(const char *name)
105244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
105344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
105444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
105544d362409d5469aed47d19e7908d19bd194493aThomas Graf
105644d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
105744d362409d5469aed47d19e7908d19bd194493aThomas Graf
105844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
105944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Link Statistics Translations
106044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
106144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
106244d362409d5469aed47d19e7908d19bd194493aThomas Graf
106344d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct trans_tbl link_stats[] = {
106444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_PACKETS, rx_packets)
106544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_PACKETS, tx_packets)
106644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_BYTES, rx_bytes)
106744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_BYTES, tx_bytes)
106844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_ERRORS, rx_errors)
106944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_ERRORS, tx_errors)
107044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
107144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
107244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
107344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
107444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
107544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
107644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
107744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
107844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
107944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
108044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
108144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
108244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
108344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
108444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
108544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_COLLISIONS, tx_collision)
108644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_MULTICAST, multicast)
108744d362409d5469aed47d19e7908d19bd194493aThomas Graf};
108844d362409d5469aed47d19e7908d19bd194493aThomas Graf
108944d362409d5469aed47d19e7908d19bd194493aThomas Grafchar *rtnl_link_stat2str(int st, char *buf, size_t len)
109044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
109144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
109244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
109344d362409d5469aed47d19e7908d19bd194493aThomas Graf
109444d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_link_str2stat(const char *name)
109544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
109644d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
109744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
109844d362409d5469aed47d19e7908d19bd194493aThomas Graf
109944d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
110044d362409d5469aed47d19e7908d19bd194493aThomas Graf
110144d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
11023ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf * @name Link Operstate Translations
11033ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf * @{
11043ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf */
11053ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
11063ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafstatic struct trans_tbl link_operstates[] = {
11073ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_OPER_UNKNOWN, unknown)
11083ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_OPER_NOTPRESENT, notpresent)
11093ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_OPER_DOWN, down)
11103ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
11113ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_OPER_TESTING, testing)
11123ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_OPER_DORMANT, dormant)
11133ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_OPER_UP, up)
11143ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf};
11153ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
11163ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafchar *rtnl_link_operstate2str(int st, char *buf, size_t len)
11173ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
11183ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	return __type2str(st, buf, len, link_operstates,
11193ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf			  ARRAY_SIZE(link_operstates));
11203ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
11213ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
11223ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafint rtnl_link_str2operstate(const char *name)
11233ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
11243ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	return __str2type(name, link_operstates,
11253ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf			  ARRAY_SIZE(link_operstates));
11263ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
11273ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
11283ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf/** @} */
11293ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
11303ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf/**
11313ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf * @name Link Mode Translations
11323ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf * @{
11333ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf */
11343ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
11353ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafstatic struct trans_tbl link_modes[] = {
11363ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_LINK_MODE_DEFAULT, default)
11373ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_LINK_MODE_DORMANT, dormant)
11383ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf};
11393ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
11403ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafchar *rtnl_link_mode2str(int st, char *buf, size_t len)
11413ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
11423ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
11433ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
11443ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
11453ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafint rtnl_link_str2mode(const char *name)
11463ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
11473ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
11483ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
11493ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
11503ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf/** @} */
11513ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
11523ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf/**
115344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Attributes
115444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
115544d362409d5469aed47d19e7908d19bd194493aThomas Graf */
115644d362409d5469aed47d19e7908d19bd194493aThomas Graf
115744d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc)
115844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
115944d362409d5469aed47d19e7908d19bd194493aThomas Graf	strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1);
116044d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_QDISC;
116144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
116244d362409d5469aed47d19e7908d19bd194493aThomas Graf
116344d362409d5469aed47d19e7908d19bd194493aThomas Grafchar *rtnl_link_get_qdisc(struct rtnl_link *link)
116444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
116544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_QDISC)
116644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return link->l_qdisc;
116744d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
116844d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
116944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
117044d362409d5469aed47d19e7908d19bd194493aThomas Graf
117144d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_name(struct rtnl_link *link, const char *name)
117244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
117344d362409d5469aed47d19e7908d19bd194493aThomas Graf	strncpy(link->l_name, name, sizeof(link->l_name) - 1);
117444d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_IFNAME;
117544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
117644d362409d5469aed47d19e7908d19bd194493aThomas Graf
117744d362409d5469aed47d19e7908d19bd194493aThomas Grafchar *rtnl_link_get_name(struct rtnl_link *link)
117844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
117944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_IFNAME)
118044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return link->l_name;
118144d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
118244d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
118344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
118444d362409d5469aed47d19e7908d19bd194493aThomas Graf
118544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
118644d362409d5469aed47d19e7908d19bd194493aThomas Graf				 struct nl_addr *new, int flag)
118744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
118844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (*pos)
118944d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_put(*pos);
119044d362409d5469aed47d19e7908d19bd194493aThomas Graf
119144d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_get(new);
119244d362409d5469aed47d19e7908d19bd194493aThomas Graf	*pos = new;
119344d362409d5469aed47d19e7908d19bd194493aThomas Graf
119444d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= flag;
119544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
119644d362409d5469aed47d19e7908d19bd194493aThomas Graf
119744d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
119844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
119944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
120044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
120144d362409d5469aed47d19e7908d19bd194493aThomas Graf
120244d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
120344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
120444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_ADDR)
120544d362409d5469aed47d19e7908d19bd194493aThomas Graf		return link->l_addr;
120644d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
120744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
120844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
120944d362409d5469aed47d19e7908d19bd194493aThomas Graf
121044d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd)
121144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
121244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD);
121344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
121444d362409d5469aed47d19e7908d19bd194493aThomas Graf
121544d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
121644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
121744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_BRD)
121844d362409d5469aed47d19e7908d19bd194493aThomas Graf		return link->l_bcast;
121944d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
122044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
122144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
122244d362409d5469aed47d19e7908d19bd194493aThomas Graf
122344d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
122444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
122544d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_flag_mask |= flags;
122644d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_flags |= flags;
122744d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_FLAGS;
122844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
122944d362409d5469aed47d19e7908d19bd194493aThomas Graf
123044d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
123144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
123244d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_flag_mask |= flags;
123344d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_flags &= ~flags;
123444d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_FLAGS;
123544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
123644d362409d5469aed47d19e7908d19bd194493aThomas Graf
123744d362409d5469aed47d19e7908d19bd194493aThomas Grafunsigned int rtnl_link_get_flags(struct rtnl_link *link)
123844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
123944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return link->l_flags;
124044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
124144d362409d5469aed47d19e7908d19bd194493aThomas Graf
124244d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_family(struct rtnl_link *link, int family)
124344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
124444d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_family = family;
124544d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_FAMILY;
124644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
124744d362409d5469aed47d19e7908d19bd194493aThomas Graf
124844d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_link_get_family(struct rtnl_link *link)
124944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
125044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->l_family & LINK_ATTR_FAMILY)
125144d362409d5469aed47d19e7908d19bd194493aThomas Graf		return link->l_family;
125244d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
125344d362409d5469aed47d19e7908d19bd194493aThomas Graf		return AF_UNSPEC;
125444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
125544d362409d5469aed47d19e7908d19bd194493aThomas Graf
125644d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
125744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
125844d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_arptype = arptype;
125944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
126044d362409d5469aed47d19e7908d19bd194493aThomas Graf
126144d362409d5469aed47d19e7908d19bd194493aThomas Grafunsigned int rtnl_link_get_arptype(struct rtnl_link *link)
126244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
126344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return link->l_arptype;
126444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
126544d362409d5469aed47d19e7908d19bd194493aThomas Graf
126644d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
126744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
126844d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_index = ifindex;
126944d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_IFINDEX;
127044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
127144d362409d5469aed47d19e7908d19bd194493aThomas Graf
127244d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_link_get_ifindex(struct rtnl_link *link)
127344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
1274b4fbe1d34d6f54045b5c6236d86aacd4340ec83dThomas Graf	return link->l_index;
127544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
127644d362409d5469aed47d19e7908d19bd194493aThomas Graf
127744d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
127844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
127944d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_mtu = mtu;
128044d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_MTU;
128144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
128244d362409d5469aed47d19e7908d19bd194493aThomas Graf
128344d362409d5469aed47d19e7908d19bd194493aThomas Grafunsigned int rtnl_link_get_mtu(struct rtnl_link *link)
128444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
128544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_MTU)
128644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return link->l_mtu;
128744d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
128844d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 0;
128944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
129044d362409d5469aed47d19e7908d19bd194493aThomas Graf
129144d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
129244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
129344d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_txqlen = txqlen;
129444d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_TXQLEN;
129544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
129644d362409d5469aed47d19e7908d19bd194493aThomas Graf
129744d362409d5469aed47d19e7908d19bd194493aThomas Grafunsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
129844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
129944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_TXQLEN)
130044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return link->l_txqlen;
130144d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
130244d362409d5469aed47d19e7908d19bd194493aThomas Graf		return UINT_MAX;
130344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
130444d362409d5469aed47d19e7908d19bd194493aThomas Graf
130544d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
130644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
130744d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_weight = weight;
130844d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_WEIGHT;
130944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
131044d362409d5469aed47d19e7908d19bd194493aThomas Graf
131144d362409d5469aed47d19e7908d19bd194493aThomas Grafunsigned int rtnl_link_get_weight(struct rtnl_link *link)
131244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
131344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_WEIGHT)
131444d362409d5469aed47d19e7908d19bd194493aThomas Graf		return link->l_weight;
131544d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
131644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return UINT_MAX;
131744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
131844d362409d5469aed47d19e7908d19bd194493aThomas Graf
131944d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_link(struct rtnl_link *link, int ifindex)
132044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
132144d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_link = ifindex;
132244d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_LINK;
132344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
132444d362409d5469aed47d19e7908d19bd194493aThomas Graf
132544d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_link_get_link(struct rtnl_link *link)
132644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
1327b4fbe1d34d6f54045b5c6236d86aacd4340ec83dThomas Graf	return link->l_link;
132844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
132944d362409d5469aed47d19e7908d19bd194493aThomas Graf
133044d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_master(struct rtnl_link *link, int ifindex)
133144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
133244d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_master = ifindex;
133344d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_MASTER;
133444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
133544d362409d5469aed47d19e7908d19bd194493aThomas Graf
133644d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_link_get_master(struct rtnl_link *link)
133744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
1338b4fbe1d34d6f54045b5c6236d86aacd4340ec83dThomas Graf	return link->l_master;
133944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
134044d362409d5469aed47d19e7908d19bd194493aThomas Graf
13413ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafvoid rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate)
13423ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
13433ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	link->l_operstate = operstate;
13443ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	link->ce_mask |= LINK_ATTR_OPERSTATE;
13453ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
13463ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
13473ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafuint8_t rtnl_link_get_operstate(struct rtnl_link *link)
13483ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
13493ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	if (link->ce_mask & LINK_ATTR_OPERSTATE)
13503ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		return link->l_operstate;
13513ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	else
13523ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		return IF_OPER_UNKNOWN;
13533ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
13543ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
13553ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafvoid rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t linkmode)
13563ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
13573ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	link->l_linkmode = linkmode;
13583ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	link->ce_mask |= LINK_ATTR_LINKMODE;
13593ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
13603ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
13613ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafuint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
13623ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
13633ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	if (link->ce_mask & LINK_ATTR_LINKMODE)
13643ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		return link->l_linkmode;
13653ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	else
13663ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		return IF_LINK_MODE_DEFAULT;
13673ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
13683ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
136944d362409d5469aed47d19e7908d19bd194493aThomas Grafuint64_t rtnl_link_get_stat(struct rtnl_link *link, int id)
137044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
137144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (id < 0 || id > RTNL_LINK_STATS_MAX)
137244d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 0;
137344d362409d5469aed47d19e7908d19bd194493aThomas Graf
137444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return link->l_stats[id];
137544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
137644d362409d5469aed47d19e7908d19bd194493aThomas Graf
1377a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf/**
1378a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * Specify the info type of a link
1379a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * @arg link	link object
1380a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * @arg type	info type
1381a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf *
1382a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * Looks up the info type and prepares the link to store info type
1383a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * specific attributes. If an info type has been assigned already
1384a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * it will be released with all changes lost.
1385a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf *
1386a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * @return 0 on success or a negative errror code.
1387a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf */
1388a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Grafint rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
1389a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf{
1390a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	struct rtnl_link_info_ops *io;
1391a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	int err;
1392a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
1393a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if ((io = rtnl_link_info_ops_lookup(type)) == NULL)
13948a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_OPNOTSUPP;
1395a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
1396a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if (link->l_info_ops)
1397a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		release_link_info(link);
1398a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
1399a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if ((err = io->io_alloc(link)) < 0)
1400a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		return err;
1401a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
1402a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	link->l_info_ops = io;
1403a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
1404a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	return 0;
1405a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf}
1406a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
1407a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf/**
1408a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * Return info type of a link
1409a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * @arg link	link object
1410a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf *
1411a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * @note The returned pointer is only valid as long as the link exists
1412a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * @return Info type name or NULL if unknown.
1413a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf */
1414a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Grafchar *rtnl_link_get_info_type(struct rtnl_link *link)
1415a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf{
1416a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if (link->l_info_ops)
1417a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		return link->l_info_ops->io_name;
1418a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	else
1419a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		return NULL;
1420a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf}
1421a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
142244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
142344d362409d5469aed47d19e7908d19bd194493aThomas Graf
142444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_object_ops link_obj_ops = {
142544d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_name		= "route/link",
142644d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_size		= sizeof(struct rtnl_link),
142744d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_free_data		= link_free_data,
142844d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_clone		= link_clone,
1429d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	.oo_dump = {
1430d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_LINE]	= link_dump_line,
1431d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_DETAILS]	= link_dump_details,
1432d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_STATS]	= link_dump_stats,
1433d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_ENV]	= link_dump_env,
1434d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	},
143544d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_compare		= link_compare,
143644d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_attrs2str		= link_attrs2str,
143744d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_id_attrs		= LINK_ATTR_IFINDEX,
143844d362409d5469aed47d19e7908d19bd194493aThomas Graf};
143944d362409d5469aed47d19e7908d19bd194493aThomas Graf
144044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_af_group link_groups[] = {
144144d362409d5469aed47d19e7908d19bd194493aThomas Graf	{ AF_UNSPEC,	RTNLGRP_LINK },
144244d362409d5469aed47d19e7908d19bd194493aThomas Graf	{ END_OF_GROUP_LIST },
144344d362409d5469aed47d19e7908d19bd194493aThomas Graf};
144444d362409d5469aed47d19e7908d19bd194493aThomas Graf
144544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_cache_ops rtnl_link_ops = {
144644d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_name		= "route/link",
144744d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_hdrsize		= sizeof(struct ifinfomsg),
144844d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_msgtypes		= {
144944d362409d5469aed47d19e7908d19bd194493aThomas Graf					{ RTM_NEWLINK, NL_ACT_NEW, "new" },
145044d362409d5469aed47d19e7908d19bd194493aThomas Graf					{ RTM_DELLINK, NL_ACT_DEL, "del" },
145144d362409d5469aed47d19e7908d19bd194493aThomas Graf					{ RTM_GETLINK, NL_ACT_GET, "get" },
145244d362409d5469aed47d19e7908d19bd194493aThomas Graf					END_OF_MSGTYPES_LIST,
145344d362409d5469aed47d19e7908d19bd194493aThomas Graf				  },
145444d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_protocol		= NETLINK_ROUTE,
145544d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_groups		= link_groups,
145644d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_request_update	= link_request_update,
145744d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_msg_parser		= link_msg_parser,
145844d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_obj_ops		= &link_obj_ops,
145944d362409d5469aed47d19e7908d19bd194493aThomas Graf};
146044d362409d5469aed47d19e7908d19bd194493aThomas Graf
146144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void __init link_init(void)
146244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
146344d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_cache_mngt_register(&rtnl_link_ops);
146444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
146544d362409d5469aed47d19e7908d19bd194493aThomas Graf
146644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void __exit link_exit(void)
146744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
146844d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_cache_mngt_unregister(&rtnl_link_ops);
146944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
147044d362409d5469aed47d19e7908d19bd194493aThomas Graf
147144d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
1472