link.c revision ef50a38fbd8682a5c9efd559e7db68664977f080
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 Graf	if (err < 0)
42144d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto errout;
42244d362409d5469aed47d19e7908d19bd194493aThomas Graf
423155ad439a49df034ec58ee4218834bc5b0120515Thomas Graf	err = P_ACCEPT;
42444d362409d5469aed47d19e7908d19bd194493aThomas Graf
42544d362409d5469aed47d19e7908d19bd194493aThomas Graferrout:
42644d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_link_put(link);
42744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return err;
42844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
42944d362409d5469aed47d19e7908d19bd194493aThomas Graf
4301155370f520cb64657e25153255cf7dc1424317fThomas Grafstatic int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
43144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
4321155370f520cb64657e25153255cf7dc1424317fThomas Graf	return nl_rtgen_request(sk, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
43344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
43444d362409d5469aed47d19e7908d19bd194493aThomas Graf
43544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int link_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
43644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
43744d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[128];
43844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cache *cache = dp_cache(obj);
43944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link = (struct rtnl_link *) obj;
44044d362409d5469aed47d19e7908d19bd194493aThomas Graf	int line = 1;
44144d362409d5469aed47d19e7908d19bd194493aThomas Graf
442a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	dp_dump(p, "%s %s ", link->l_name,
443a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf			     nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
4443ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
4453ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	if (link->l_addr && !nl_addr_iszero(link->l_addr))
4463ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		dp_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
44744d362409d5469aed47d19e7908d19bd194493aThomas Graf
44844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_MASTER) {
44944d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
45044d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "master %s ", master ? master->l_name : "inv");
45144d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (master)
45244d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_link_put(master);
45344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
45444d362409d5469aed47d19e7908d19bd194493aThomas Graf
45544d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
45644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (buf[0])
457a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		dp_dump(p, "<%s> ", buf);
458a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
459a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if (link->ce_mask & LINK_ATTR_LINK) {
460a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
461a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		dp_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
462a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		if (ll)
463a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf			rtnl_link_put(ll);
464a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	}
465a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
466a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_BRIEF])
467a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		line = link->l_info_ops->io_dump[NL_DUMP_BRIEF](link, p, line);
46844d362409d5469aed47d19e7908d19bd194493aThomas Graf
46944d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump(p, "\n");
47044d362409d5469aed47d19e7908d19bd194493aThomas Graf
47144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return line;
47244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
47344d362409d5469aed47d19e7908d19bd194493aThomas Graf
47444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int link_dump_full(struct nl_object *obj, struct nl_dump_params *p)
47544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
47644d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link = (struct rtnl_link *) obj;
47744d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[64];
47844d362409d5469aed47d19e7908d19bd194493aThomas Graf	int line;
47944d362409d5469aed47d19e7908d19bd194493aThomas Graf
48044d362409d5469aed47d19e7908d19bd194493aThomas Graf	line = link_dump_brief(obj, p);
48144d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_new_line(p, line++);
48244d362409d5469aed47d19e7908d19bd194493aThomas Graf
4833ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	dp_dump(p, "    mtu %u ", link->l_mtu);
4843ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	dp_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
48544d362409d5469aed47d19e7908d19bd194493aThomas Graf
48644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_QDISC)
48744d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "qdisc %s ", link->l_qdisc);
48844d362409d5469aed47d19e7908d19bd194493aThomas Graf
48944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
49044d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "irq %u ", link->l_map.lm_irq);
49144d362409d5469aed47d19e7908d19bd194493aThomas Graf
49244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_IFINDEX)
49344d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "index %u ", link->l_index);
49444d362409d5469aed47d19e7908d19bd194493aThomas Graf
4953ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
4963ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	dp_dump(p, "\n");
4973ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	dp_new_line(p, line++);
4983ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
4993ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	dp_dump(p, "    ");
5003ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
50144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_BRD)
5023ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		dp_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
50344d362409d5469aed47d19e7908d19bd194493aThomas Graf						   sizeof(buf)));
50444d362409d5469aed47d19e7908d19bd194493aThomas Graf
5053ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
5063ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	    link->l_operstate != IF_OPER_UNKNOWN) {
5073ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
5083ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		dp_dump(p, "state %s ", buf);
5093ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	}
5103ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
5113ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	dp_dump(p, "mode %s\n",
5123ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
51344d362409d5469aed47d19e7908d19bd194493aThomas Graf
514a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_FULL])
515a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		line = link->l_info_ops->io_dump[NL_DUMP_FULL](link, p, line);
516a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
51744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return line;
51844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
51944d362409d5469aed47d19e7908d19bd194493aThomas Graf
52044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
52144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
52244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link = (struct rtnl_link *) obj;
52344d362409d5469aed47d19e7908d19bd194493aThomas Graf	char *unit, fmt[64];
52444d362409d5469aed47d19e7908d19bd194493aThomas Graf	float res;
52544d362409d5469aed47d19e7908d19bd194493aThomas Graf	int line;
52644d362409d5469aed47d19e7908d19bd194493aThomas Graf
52744d362409d5469aed47d19e7908d19bd194493aThomas Graf	line = link_dump_full(obj, p);
52844d362409d5469aed47d19e7908d19bd194493aThomas Graf
52944d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "    Stats:    bytes    packets     errors "
53044d362409d5469aed47d19e7908d19bd194493aThomas Graf				"   dropped   fifo-err compressed\n");
53144d362409d5469aed47d19e7908d19bd194493aThomas Graf
53244d362409d5469aed47d19e7908d19bd194493aThomas Graf	res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
53344d362409d5469aed47d19e7908d19bd194493aThomas Graf
5347f6b7a8eea0334b34d58dec72c66121a76f08958Thomas Graf	strcpy(fmt, "     RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
53544d362409d5469aed47d19e7908d19bd194493aThomas Graf	fmt[9] = *unit == 'B' ? '9' : '7';
53644d362409d5469aed47d19e7908d19bd194493aThomas Graf
53744d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, fmt,
53844d362409d5469aed47d19e7908d19bd194493aThomas Graf		res, unit,
53944d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_PACKETS],
54044d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_ERRORS],
54144d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_DROPPED],
54244d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_FIFO_ERR],
54344d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_COMPRESSED]);
54444d362409d5469aed47d19e7908d19bd194493aThomas Graf
54544d362409d5469aed47d19e7908d19bd194493aThomas Graf	res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
54644d362409d5469aed47d19e7908d19bd194493aThomas Graf
5477f6b7a8eea0334b34d58dec72c66121a76f08958Thomas Graf	strcpy(fmt, "     TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
54844d362409d5469aed47d19e7908d19bd194493aThomas Graf	fmt[9] = *unit == 'B' ? '9' : '7';
54944d362409d5469aed47d19e7908d19bd194493aThomas Graf
55044d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, fmt,
55144d362409d5469aed47d19e7908d19bd194493aThomas Graf		res, unit,
55244d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_PACKETS],
55344d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_ERRORS],
55444d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_DROPPED],
55544d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_FIFO_ERR],
55644d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_COMPRESSED]);
55744d362409d5469aed47d19e7908d19bd194493aThomas Graf
55844d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "    Errors:  length       over        crc "
55944d362409d5469aed47d19e7908d19bd194493aThomas Graf				"     frame     missed  multicast\n");
56044d362409d5469aed47d19e7908d19bd194493aThomas Graf
5617f6b7a8eea0334b34d58dec72c66121a76f08958Thomas Graf	dp_dump_line(p, line++, "     RX  %10" PRIu64 " %10" PRIu64 " %10"
56244d362409d5469aed47d19e7908d19bd194493aThomas Graf				PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
56344d362409d5469aed47d19e7908d19bd194493aThomas Graf				PRIu64 "\n",
56444d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_LEN_ERR],
56544d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_OVER_ERR],
56644d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_CRC_ERR],
56744d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_FRAME_ERR],
56844d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_RX_MISSED_ERR],
56944d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_MULTICAST]);
57044d362409d5469aed47d19e7908d19bd194493aThomas Graf
5717f6b7a8eea0334b34d58dec72c66121a76f08958Thomas Graf	dp_dump_line(p, line++, "            aborted    carrier  heartbeat "
57244d362409d5469aed47d19e7908d19bd194493aThomas Graf				"    window  collision\n");
57344d362409d5469aed47d19e7908d19bd194493aThomas Graf
5747f6b7a8eea0334b34d58dec72c66121a76f08958Thomas Graf	dp_dump_line(p, line++, "     TX  %10" PRIu64 " %10" PRIu64 " %10"
57544d362409d5469aed47d19e7908d19bd194493aThomas Graf				PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
57644d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_ABORT_ERR],
57744d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
57844d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
57944d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_WIN_ERR],
58044d362409d5469aed47d19e7908d19bd194493aThomas Graf		link->l_stats[RTNL_LINK_TX_COLLISIONS]);
58144d362409d5469aed47d19e7908d19bd194493aThomas Graf
582a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
583a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		line = link->l_info_ops->io_dump[NL_DUMP_STATS](link, p, line);
584a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
58544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return line;
58644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
58744d362409d5469aed47d19e7908d19bd194493aThomas Graf
58844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int link_dump_xml(struct nl_object *obj, struct nl_dump_params *p)
58944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
59044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link = (struct rtnl_link *) obj;
59144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cache *cache = dp_cache(obj);
59244d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[128];
59344d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i, line = 0;
59444d362409d5469aed47d19e7908d19bd194493aThomas Graf
59544d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "<link name=\"%s\" index=\"%u\">\n",
59644d362409d5469aed47d19e7908d19bd194493aThomas Graf		     link->l_name, link->l_index);
59744d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "  <family>%s</family>\n",
59844d362409d5469aed47d19e7908d19bd194493aThomas Graf		     nl_af2str(link->l_family, buf, sizeof(buf)));
59944d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "  <arptype>%s</arptype>\n",
60044d362409d5469aed47d19e7908d19bd194493aThomas Graf		     nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
60144d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "  <address>%s</address>\n",
60244d362409d5469aed47d19e7908d19bd194493aThomas Graf		     nl_addr2str(link->l_addr, buf, sizeof(buf)));
60344d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "  <mtu>%u</mtu>\n", link->l_mtu);
60444d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "  <txqlen>%u</txqlen>\n", link->l_txqlen);
60544d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "  <weight>%u</weight>\n", link->l_weight);
60644d362409d5469aed47d19e7908d19bd194493aThomas Graf
60744d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
60844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (buf[0])
60944d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <flags>%s</flags>\n", buf);
61044d362409d5469aed47d19e7908d19bd194493aThomas Graf
61144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_QDISC)
61244d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <qdisc>%s</qdisc>\n", link->l_qdisc);
61344d362409d5469aed47d19e7908d19bd194493aThomas Graf
61444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_LINK) {
61544d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
61644d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <link>%s</link>\n",
61744d362409d5469aed47d19e7908d19bd194493aThomas Graf			     ll ? ll->l_name : "none");
61844d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (ll)
61944d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_link_put(ll);
62044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
62144d362409d5469aed47d19e7908d19bd194493aThomas Graf
62244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_MASTER) {
62344d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
62444d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <master>%s</master>\n",
62544d362409d5469aed47d19e7908d19bd194493aThomas Graf			     master ? master->l_name : "none");
62644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (master)
62744d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_link_put(master);
62844d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
62944d362409d5469aed47d19e7908d19bd194493aThomas Graf
63044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_BRD)
63144d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <broadcast>%s</broadcast>\n",
63244d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(link->l_bcast, buf, sizeof(buf)));
63344d362409d5469aed47d19e7908d19bd194493aThomas Graf
63444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_STATS) {
63544d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <stats>\n");
63644d362409d5469aed47d19e7908d19bd194493aThomas Graf		for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
63744d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_link_stat2str(i, buf, sizeof(buf));
63844d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump_line(p, line++,
63944d362409d5469aed47d19e7908d19bd194493aThomas Graf				     "    <%s>%" PRIu64 "</%s>\n",
64044d362409d5469aed47d19e7908d19bd194493aThomas Graf				     buf, link->l_stats[i], buf);
64144d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
64244d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  </stats>\n");
64344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
64444d362409d5469aed47d19e7908d19bd194493aThomas Graf
645a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_XML]) {
646a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		dp_dump_line(p, line++, "  <info>\n");
647a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		line = link->l_info_ops->io_dump[NL_DUMP_XML](link, p, line);
648a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		dp_dump_line(p, line++, "  </info>\n");
649a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	}
650a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
65144d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "</link>\n");
65244d362409d5469aed47d19e7908d19bd194493aThomas Graf
65344d362409d5469aed47d19e7908d19bd194493aThomas Graf#if 0
65444d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint32_t	l_change;	/**< Change mask */
65544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_lifmap l_map;	/**< Interface device mapping */
65644d362409d5469aed47d19e7908d19bd194493aThomas Graf#endif
65744d362409d5469aed47d19e7908d19bd194493aThomas Graf
65844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return line;
65944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
66044d362409d5469aed47d19e7908d19bd194493aThomas Graf
66144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int link_dump_env(struct nl_object *obj, struct nl_dump_params *p)
66244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
66344d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link = (struct rtnl_link *) obj;
66444d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cache *cache = dp_cache(obj);
66544d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[128];
66644d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i, line = 0;
66744d362409d5469aed47d19e7908d19bd194493aThomas Graf
66844d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "LINK_NAME=%s\n", link->l_name);
66944d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "LINK_IFINDEX=%u\n", link->l_index);
67044d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "LINK_FAMILY=%s\n",
67144d362409d5469aed47d19e7908d19bd194493aThomas Graf		     nl_af2str(link->l_family, buf, sizeof(buf)));
67244d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "LINK_TYPE=%s\n",
67344d362409d5469aed47d19e7908d19bd194493aThomas Graf		     nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
67444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_ADDR)
67544d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "LINK_ADDRESS=%s\n",
67644d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(link->l_addr, buf, sizeof(buf)));
67744d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "LINK_MTU=%u\n", link->l_mtu);
67844d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "LINK_TXQUEUELEN=%u\n", link->l_txqlen);
67944d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "LINK_WEIGHT=%u\n", link->l_weight);
68044d362409d5469aed47d19e7908d19bd194493aThomas Graf
68144d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_link_flags2str(link->l_flags & ~IFF_RUNNING, buf, sizeof(buf));
68244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (buf[0])
68344d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "LINK_FLAGS=%s\n", buf);
68444d362409d5469aed47d19e7908d19bd194493aThomas Graf
68544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_QDISC)
68644d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "LINK_QDISC=%s\n", link->l_qdisc);
68744d362409d5469aed47d19e7908d19bd194493aThomas Graf
68844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_LINK) {
68944d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
69044d362409d5469aed47d19e7908d19bd194493aThomas Graf
69144d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "LINK_LINK_IFINDEX=%d\n", link->l_link);
69244d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (ll) {
69344d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump_line(p, line++, "LINK_LINK_IFNAME=%s\n",
69444d362409d5469aed47d19e7908d19bd194493aThomas Graf				     ll->l_name);
69544d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_link_put(ll);
69644d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
69744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
69844d362409d5469aed47d19e7908d19bd194493aThomas Graf
69944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_MASTER) {
70044d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
70144d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "LINK_MASTER=%s\n",
70244d362409d5469aed47d19e7908d19bd194493aThomas Graf			     master ? master->l_name : "none");
70344d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (master)
70444d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_link_put(master);
70544d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
70644d362409d5469aed47d19e7908d19bd194493aThomas Graf
70744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_BRD)
70844d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "LINK_BROADCAST=%s\n",
70944d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(link->l_bcast, buf, sizeof(buf)));
71044d362409d5469aed47d19e7908d19bd194493aThomas Graf
71144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_STATS) {
71244d362409d5469aed47d19e7908d19bd194493aThomas Graf		for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
71344d362409d5469aed47d19e7908d19bd194493aThomas Graf			char *c = buf;
71444d362409d5469aed47d19e7908d19bd194493aThomas Graf
71544d362409d5469aed47d19e7908d19bd194493aThomas Graf			sprintf(buf, "LINK_");
71644d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_link_stat2str(i, buf + 5, sizeof(buf) - 5);
71744d362409d5469aed47d19e7908d19bd194493aThomas Graf			while (*c) {
71844d362409d5469aed47d19e7908d19bd194493aThomas Graf				*c = toupper(*c);
71944d362409d5469aed47d19e7908d19bd194493aThomas Graf				c++;
72044d362409d5469aed47d19e7908d19bd194493aThomas Graf			}
72144d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump_line(p, line++,
72244d362409d5469aed47d19e7908d19bd194493aThomas Graf				     "%s=%" PRIu64 "\n", buf, link->l_stats[i]);
72344d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
72444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
72544d362409d5469aed47d19e7908d19bd194493aThomas Graf
726a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_ENV])
727a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		line = link->l_info_ops->io_dump[NL_DUMP_ENV](link, p, line);
728a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
72944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return line;
73044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
73144d362409d5469aed47d19e7908d19bd194493aThomas Graf
73244d362409d5469aed47d19e7908d19bd194493aThomas Graf#if 0
73344d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
73444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
73544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *l = (struct rtnl_link *) a;
73644d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cache *c = dp_cache(a);
73744d362409d5469aed47d19e7908d19bd194493aThomas Graf	int nevents = 0;
73844d362409d5469aed47d19e7908d19bd194493aThomas Graf
73944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (l->l_change == ~0U) {
74044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (l->ce_msgtype == RTM_NEWLINK)
74144d362409d5469aed47d19e7908d19bd194493aThomas Graf			cb->le_register(l);
74244d362409d5469aed47d19e7908d19bd194493aThomas Graf		else
74344d362409d5469aed47d19e7908d19bd194493aThomas Graf			cb->le_unregister(l);
74444d362409d5469aed47d19e7908d19bd194493aThomas Graf
74544d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 1;
74644d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
74744d362409d5469aed47d19e7908d19bd194493aThomas Graf
74844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (l->l_change & IFF_SLAVE) {
74944d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (l->l_flags & IFF_SLAVE) {
75044d362409d5469aed47d19e7908d19bd194493aThomas Graf			struct rtnl_link *m = rtnl_link_get(c, l->l_master);
75144d362409d5469aed47d19e7908d19bd194493aThomas Graf			cb->le_new_bonding(l, m);
75244d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (m)
75344d362409d5469aed47d19e7908d19bd194493aThomas Graf				rtnl_link_put(m);
75444d362409d5469aed47d19e7908d19bd194493aThomas Graf		} else
75544d362409d5469aed47d19e7908d19bd194493aThomas Graf			cb->le_cancel_bonding(l);
75644d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
75744d362409d5469aed47d19e7908d19bd194493aThomas Graf
75844d362409d5469aed47d19e7908d19bd194493aThomas Graf#if 0
75944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
76044d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "link %s changed state to %s.\n",
76144d362409d5469aed47d19e7908d19bd194493aThomas Graf			l->l_name, l->l_flags & IFF_UP ? "up" : "down");
76244d362409d5469aed47d19e7908d19bd194493aThomas Graf
76344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (l->l_change & IFF_PROMISC) {
76444d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_new_line(p, line++);
76544d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "link %s %s promiscuous mode.\n",
76644d362409d5469aed47d19e7908d19bd194493aThomas Graf		    l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
76744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
76844d362409d5469aed47d19e7908d19bd194493aThomas Graf
76944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (line == 0)
77044d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "link %s sent unknown event.\n",
77144d362409d5469aed47d19e7908d19bd194493aThomas Graf			     l->l_name);
77244d362409d5469aed47d19e7908d19bd194493aThomas Graf#endif
77344d362409d5469aed47d19e7908d19bd194493aThomas Graf
77444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return nevents;
77544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
77644d362409d5469aed47d19e7908d19bd194493aThomas Graf#endif
77744d362409d5469aed47d19e7908d19bd194493aThomas Graf
77844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int link_compare(struct nl_object *_a, struct nl_object *_b,
77944d362409d5469aed47d19e7908d19bd194493aThomas Graf			uint32_t attrs, int flags)
78044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
78144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *a = (struct rtnl_link *) _a;
78244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *b = (struct rtnl_link *) _b;
78344d362409d5469aed47d19e7908d19bd194493aThomas Graf	int diff = 0;
78444d362409d5469aed47d19e7908d19bd194493aThomas Graf
78544d362409d5469aed47d19e7908d19bd194493aThomas Graf#define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
78644d362409d5469aed47d19e7908d19bd194493aThomas Graf
78744d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(IFINDEX,	a->l_index != b->l_index);
78844d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(MTU,		a->l_mtu != b->l_mtu);
78944d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(LINK,		a->l_link != b->l_link);
79044d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(TXQLEN,	a->l_txqlen != b->l_txqlen);
79144d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(WEIGHT,	a->l_weight != b->l_weight);
79244d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(MASTER,	a->l_master != b->l_master);
79344d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(FAMILY,	a->l_family != b->l_family);
7943ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	diff |= LINK_DIFF(OPERSTATE,	a->l_operstate != b->l_operstate);
7953ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	diff |= LINK_DIFF(LINKMODE,	a->l_linkmode != b->l_linkmode);
79644d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(QDISC,	strcmp(a->l_qdisc, b->l_qdisc));
79744d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(IFNAME,	strcmp(a->l_name, b->l_name));
79844d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(ADDR,		nl_addr_cmp(a->l_addr, b->l_addr));
79944d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= LINK_DIFF(BRD,		nl_addr_cmp(a->l_bcast, b->l_bcast));
80044d362409d5469aed47d19e7908d19bd194493aThomas Graf
801535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (flags & LOOSE_COMPARISON)
80244d362409d5469aed47d19e7908d19bd194493aThomas Graf		diff |= LINK_DIFF(FLAGS,
80344d362409d5469aed47d19e7908d19bd194493aThomas Graf				  (a->l_flags ^ b->l_flags) & b->l_flag_mask);
80444d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
80544d362409d5469aed47d19e7908d19bd194493aThomas Graf		diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
80644d362409d5469aed47d19e7908d19bd194493aThomas Graf
80744d362409d5469aed47d19e7908d19bd194493aThomas Graf#undef LINK_DIFF
80844d362409d5469aed47d19e7908d19bd194493aThomas Graf
80944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return diff;
81044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
81144d362409d5469aed47d19e7908d19bd194493aThomas Graf
81244d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct trans_tbl link_attrs[] = {
81344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_MTU, mtu)
81444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_LINK, link)
81544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_TXQLEN, txqlen)
81644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_WEIGHT, weight)
81744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_MASTER, master)
81844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_QDISC, qdisc)
81944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_MAP, map)
82044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_ADDR, address)
82144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_BRD, broadcast)
82244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_FLAGS, flags)
82344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_IFNAME, name)
82444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_IFINDEX, ifindex)
82544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_FAMILY, family)
82644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_ARPTYPE, arptype)
82744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_STATS, stats)
82844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(LINK_ATTR_CHANGE, change)
8293ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(LINK_ATTR_OPERSTATE, operstate)
8303ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(LINK_ATTR_LINKMODE, linkmode)
83144d362409d5469aed47d19e7908d19bd194493aThomas Graf};
83244d362409d5469aed47d19e7908d19bd194493aThomas Graf
83344d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic char *link_attrs2str(int attrs, char *buf, size_t len)
83444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
83544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __flags2str(attrs, buf, len, link_attrs,
83644d362409d5469aed47d19e7908d19bd194493aThomas Graf			   ARRAY_SIZE(link_attrs));
83744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
83844d362409d5469aed47d19e7908d19bd194493aThomas Graf
83944d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
84044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Allocation/Freeing
84144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
84244d362409d5469aed47d19e7908d19bd194493aThomas Graf */
84344d362409d5469aed47d19e7908d19bd194493aThomas Graf
84444d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct rtnl_link *rtnl_link_alloc(void)
84544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
84644d362409d5469aed47d19e7908d19bd194493aThomas Graf	return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
84744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
84844d362409d5469aed47d19e7908d19bd194493aThomas Graf
84944d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_put(struct rtnl_link *link)
85044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
85144d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_object_put((struct nl_object *) link);
85244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
85344d362409d5469aed47d19e7908d19bd194493aThomas Graf
85444d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
85544d362409d5469aed47d19e7908d19bd194493aThomas Graf
85644d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
85744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Cache Management
85844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
85944d362409d5469aed47d19e7908d19bd194493aThomas Graf */
86044d362409d5469aed47d19e7908d19bd194493aThomas Graf
86144d362409d5469aed47d19e7908d19bd194493aThomas Graf
86244d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
86344d362409d5469aed47d19e7908d19bd194493aThomas Graf * Allocate link cache and fill in all configured links.
8641155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
8658a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * @arg result		Pointer to store resulting cache.
86644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
86744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Allocates a new link cache, initializes it properly and updates it
86844d362409d5469aed47d19e7908d19bd194493aThomas Graf * to include all links currently configured in the kernel.
86944d362409d5469aed47d19e7908d19bd194493aThomas Graf *
8708a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * @return 0 on success or a negative error code.
87144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
8721155370f520cb64657e25153255cf7dc1424317fThomas Grafint rtnl_link_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
87344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
8741155370f520cb64657e25153255cf7dc1424317fThomas Graf	return nl_cache_alloc_and_fill(&rtnl_link_ops, sk, result);
87544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
87644d362409d5469aed47d19e7908d19bd194493aThomas Graf
87744d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
87844d362409d5469aed47d19e7908d19bd194493aThomas Graf * Look up link by interface index in the provided cache
87944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cache		link cache
88044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg ifindex		link interface index
88144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
88244d362409d5469aed47d19e7908d19bd194493aThomas Graf * The caller owns a reference on the returned object and
88344d362409d5469aed47d19e7908d19bd194493aThomas Graf * must give the object back via rtnl_link_put().
88444d362409d5469aed47d19e7908d19bd194493aThomas Graf *
88544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return pointer to link inside the cache or NULL if no match was found.
88644d362409d5469aed47d19e7908d19bd194493aThomas Graf */
88744d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
88844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
88944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link;
89044d362409d5469aed47d19e7908d19bd194493aThomas Graf
89144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (cache->c_ops != &rtnl_link_ops)
89244d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
89344d362409d5469aed47d19e7908d19bd194493aThomas Graf
89444d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_list_for_each_entry(link, &cache->c_items, ce_list) {
89544d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (link->l_index == ifindex) {
89644d362409d5469aed47d19e7908d19bd194493aThomas Graf			nl_object_get((struct nl_object *) link);
89744d362409d5469aed47d19e7908d19bd194493aThomas Graf			return link;
89844d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
89944d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
90044d362409d5469aed47d19e7908d19bd194493aThomas Graf
90144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NULL;
90244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
90344d362409d5469aed47d19e7908d19bd194493aThomas Graf
90444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
90544d362409d5469aed47d19e7908d19bd194493aThomas Graf * Look up link by link name in the provided cache
90644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cache		link cache
90744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg name		link name
90844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
90944d362409d5469aed47d19e7908d19bd194493aThomas Graf * The caller owns a reference on the returned object and
91044d362409d5469aed47d19e7908d19bd194493aThomas Graf * must give the object back via rtnl_link_put().
91144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
91244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return pointer to link inside the cache or NULL if no match was found.
91344d362409d5469aed47d19e7908d19bd194493aThomas Graf */
91444d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
91544d362409d5469aed47d19e7908d19bd194493aThomas Graf					 const char *name)
91644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
91744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link;
91844d362409d5469aed47d19e7908d19bd194493aThomas Graf
91944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (cache->c_ops != &rtnl_link_ops)
92044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
92144d362409d5469aed47d19e7908d19bd194493aThomas Graf
92244d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_list_for_each_entry(link, &cache->c_items, ce_list) {
92344d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!strcmp(name, link->l_name)) {
92444d362409d5469aed47d19e7908d19bd194493aThomas Graf			nl_object_get((struct nl_object *) link);
92544d362409d5469aed47d19e7908d19bd194493aThomas Graf			return link;
92644d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
92744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
92844d362409d5469aed47d19e7908d19bd194493aThomas Graf
92944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NULL;
93044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
93144d362409d5469aed47d19e7908d19bd194493aThomas Graf
93244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
93344d362409d5469aed47d19e7908d19bd194493aThomas Graf
93444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
93544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Link Modifications
93644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
93744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
93844d362409d5469aed47d19e7908d19bd194493aThomas Graf
93944d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
94044d362409d5469aed47d19e7908d19bd194493aThomas Graf * Builds a netlink change request message to change link attributes
94144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg old		link to be changed
94244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg tmpl		template with requested changes
94344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg flags		additional netlink message flags
94444d362409d5469aed47d19e7908d19bd194493aThomas Graf *
94544d362409d5469aed47d19e7908d19bd194493aThomas Graf * Builds a new netlink message requesting a change of link attributes.
94644d362409d5469aed47d19e7908d19bd194493aThomas Graf * The netlink message header isn't fully equipped with all relevant
94744d362409d5469aed47d19e7908d19bd194493aThomas Graf * fields and must be sent out via nl_send_auto_complete() or
94844d362409d5469aed47d19e7908d19bd194493aThomas Graf * supplemented as needed.
94944d362409d5469aed47d19e7908d19bd194493aThomas Graf * \a old must point to a link currently configured in the kernel
95044d362409d5469aed47d19e7908d19bd194493aThomas Graf * and \a tmpl must contain the attributes to be changed set via
95144d362409d5469aed47d19e7908d19bd194493aThomas Graf * \c rtnl_link_set_* functions.
95244d362409d5469aed47d19e7908d19bd194493aThomas Graf *
95344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return New netlink message
95444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @note Not all attributes can be changed, see
95544d362409d5469aed47d19e7908d19bd194493aThomas Graf *       \ref link_changeable "Changeable Attributes" for more details.
95644d362409d5469aed47d19e7908d19bd194493aThomas Graf */
9578a3efffa5b3fde252675239914118664d36a2c24Thomas Grafint rtnl_link_build_change_request(struct rtnl_link *old,
9588a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				   struct rtnl_link *tmpl, int flags,
9598a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				   struct nl_msg **result)
96044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
96144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_msg *msg;
96244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct ifinfomsg ifi = {
96344d362409d5469aed47d19e7908d19bd194493aThomas Graf		.ifi_family = old->l_family,
96444d362409d5469aed47d19e7908d19bd194493aThomas Graf		.ifi_index = old->l_index,
96544d362409d5469aed47d19e7908d19bd194493aThomas Graf	};
96644d362409d5469aed47d19e7908d19bd194493aThomas Graf
96744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tmpl->ce_mask & LINK_ATTR_FLAGS) {
96844d362409d5469aed47d19e7908d19bd194493aThomas Graf		ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask;
96944d362409d5469aed47d19e7908d19bd194493aThomas Graf		ifi.ifi_flags |= tmpl->l_flags;
97044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
97144d362409d5469aed47d19e7908d19bd194493aThomas Graf
97244d362409d5469aed47d19e7908d19bd194493aThomas Graf	msg = nlmsg_alloc_simple(RTM_SETLINK, flags);
97344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!msg)
9748a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
97544d362409d5469aed47d19e7908d19bd194493aThomas Graf
97644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
97744d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto nla_put_failure;
97844d362409d5469aed47d19e7908d19bd194493aThomas Graf
97944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tmpl->ce_mask & LINK_ATTR_ADDR)
98044d362409d5469aed47d19e7908d19bd194493aThomas Graf		NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr);
98144d362409d5469aed47d19e7908d19bd194493aThomas Graf
98244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tmpl->ce_mask & LINK_ATTR_BRD)
98344d362409d5469aed47d19e7908d19bd194493aThomas Graf		NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast);
98444d362409d5469aed47d19e7908d19bd194493aThomas Graf
98544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tmpl->ce_mask & LINK_ATTR_MTU)
98644d362409d5469aed47d19e7908d19bd194493aThomas Graf		NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu);
98744d362409d5469aed47d19e7908d19bd194493aThomas Graf
98844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tmpl->ce_mask & LINK_ATTR_TXQLEN)
98944d362409d5469aed47d19e7908d19bd194493aThomas Graf		NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen);
99044d362409d5469aed47d19e7908d19bd194493aThomas Graf
99144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tmpl->ce_mask & LINK_ATTR_WEIGHT)
99244d362409d5469aed47d19e7908d19bd194493aThomas Graf		NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight);
99344d362409d5469aed47d19e7908d19bd194493aThomas Graf
99444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tmpl->ce_mask & LINK_ATTR_IFNAME)
99544d362409d5469aed47d19e7908d19bd194493aThomas Graf		NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name);
99644d362409d5469aed47d19e7908d19bd194493aThomas Graf
9973ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	if (tmpl->ce_mask & LINK_ATTR_OPERSTATE)
9983ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		NLA_PUT_U8(msg, IFLA_OPERSTATE, tmpl->l_operstate);
9993ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
10003ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	if (tmpl->ce_mask & LINK_ATTR_LINKMODE)
10013ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		NLA_PUT_U8(msg, IFLA_LINKMODE, tmpl->l_linkmode);
10023ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
1003a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if ((tmpl->ce_mask & LINK_ATTR_LINKINFO) && tmpl->l_info_ops &&
1004a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	    tmpl->l_info_ops->io_put_attrs) {
1005a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		struct nlattr *info;
1006a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
1007a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
1008a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf			goto nla_put_failure;
1009a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
1010a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		NLA_PUT_STRING(msg, IFLA_INFO_KIND, tmpl->l_info_ops->io_name);
1011a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
1012a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		if (tmpl->l_info_ops->io_put_attrs(msg, tmpl) < 0)
1013a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf			goto nla_put_failure;
1014a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
1015a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		nla_nest_end(msg, info);
1016a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	}
1017a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
10188a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	*result = msg;
10198a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return 0;
102044d362409d5469aed47d19e7908d19bd194493aThomas Graf
102144d362409d5469aed47d19e7908d19bd194493aThomas Grafnla_put_failure:
102244d362409d5469aed47d19e7908d19bd194493aThomas Graf	nlmsg_free(msg);
10238a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return -NLE_MSGSIZE;
102444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
102544d362409d5469aed47d19e7908d19bd194493aThomas Graf
102644d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
102744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Change link attributes
10281155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
102944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg old		link to be changed
103044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg tmpl		template with requested changes
103144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg flags		additional netlink message flags
103244d362409d5469aed47d19e7908d19bd194493aThomas Graf *
103344d362409d5469aed47d19e7908d19bd194493aThomas Graf * Builds a new netlink message by calling rtnl_link_build_change_request(),
103444d362409d5469aed47d19e7908d19bd194493aThomas Graf * sends the request to the kernel and waits for the next ACK to be
103544d362409d5469aed47d19e7908d19bd194493aThomas Graf * received, i.e. blocks until the request has been processed.
103644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
103744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code
103844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @note Not all attributes can be changed, see
103944d362409d5469aed47d19e7908d19bd194493aThomas Graf *       \ref link_changeable "Changeable Attributes" for more details.
104044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
10411155370f520cb64657e25153255cf7dc1424317fThomas Grafint rtnl_link_change(struct nl_sock *sk, struct rtnl_link *old,
104244d362409d5469aed47d19e7908d19bd194493aThomas Graf		     struct rtnl_link *tmpl, int flags)
104344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
104444d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_msg *msg;
10458a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	int err;
104644d362409d5469aed47d19e7908d19bd194493aThomas Graf
10478a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	if ((err = rtnl_link_build_change_request(old, tmpl, flags, &msg)) < 0)
10488a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return err;
104944d362409d5469aed47d19e7908d19bd194493aThomas Graf
1050ef50a38fbd8682a5c9efd559e7db68664977f080Thomas Graf	err = nl_send_auto_complete(sk, msg);
1051ef50a38fbd8682a5c9efd559e7db68664977f080Thomas Graf	nlmsg_free(msg);
1052ef50a38fbd8682a5c9efd559e7db68664977f080Thomas Graf	if (err < 0)
105344d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
105444d362409d5469aed47d19e7908d19bd194493aThomas Graf
10551155370f520cb64657e25153255cf7dc1424317fThomas Graf	return nl_wait_for_ack(sk);
105644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
105744d362409d5469aed47d19e7908d19bd194493aThomas Graf
105844d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
105944d362409d5469aed47d19e7908d19bd194493aThomas Graf
106044d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
106144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Name <-> Index Translations
106244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
106344d362409d5469aed47d19e7908d19bd194493aThomas Graf */
106444d362409d5469aed47d19e7908d19bd194493aThomas Graf
106544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
106644d362409d5469aed47d19e7908d19bd194493aThomas Graf * Translate an interface index to the corresponding link name
106744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cache		link cache
106844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg ifindex		link interface index
106944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg dst		destination buffer
107044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg len		length of destination buffer
107144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
107244d362409d5469aed47d19e7908d19bd194493aThomas Graf * Translates the specified interface index to the corresponding
107344d362409d5469aed47d19e7908d19bd194493aThomas Graf * link name and stores the name in the destination buffer.
107444d362409d5469aed47d19e7908d19bd194493aThomas Graf *
107544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return link name or NULL if no match was found.
107644d362409d5469aed47d19e7908d19bd194493aThomas Graf */
107744d362409d5469aed47d19e7908d19bd194493aThomas Grafchar * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
107844d362409d5469aed47d19e7908d19bd194493aThomas Graf			size_t len)
107944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
108044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link = rtnl_link_get(cache, ifindex);
108144d362409d5469aed47d19e7908d19bd194493aThomas Graf
108244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link) {
108344d362409d5469aed47d19e7908d19bd194493aThomas Graf		strncpy(dst, link->l_name, len - 1);
108444d362409d5469aed47d19e7908d19bd194493aThomas Graf		rtnl_link_put(link);
108544d362409d5469aed47d19e7908d19bd194493aThomas Graf		return dst;
108644d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
108744d362409d5469aed47d19e7908d19bd194493aThomas Graf
108844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NULL;
108944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
109044d362409d5469aed47d19e7908d19bd194493aThomas Graf
109144d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
109244d362409d5469aed47d19e7908d19bd194493aThomas Graf * Translate a link name to the corresponding interface index
109344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cache		link cache
109444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg name		link name
109544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
1096b4fbe1d34d6f54045b5c6236d86aacd4340ec83dThomas Graf * @return interface index or 0 if no match was found.
109744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
109844d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_link_name2i(struct nl_cache *cache, const char *name)
109944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
1100b4fbe1d34d6f54045b5c6236d86aacd4340ec83dThomas Graf	int ifindex = 0;
110144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_link *link;
110244d362409d5469aed47d19e7908d19bd194493aThomas Graf
110344d362409d5469aed47d19e7908d19bd194493aThomas Graf	link = rtnl_link_get_by_name(cache, name);
110444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link) {
110544d362409d5469aed47d19e7908d19bd194493aThomas Graf		ifindex = link->l_index;
110644d362409d5469aed47d19e7908d19bd194493aThomas Graf		rtnl_link_put(link);
110744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
110844d362409d5469aed47d19e7908d19bd194493aThomas Graf
110944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return ifindex;
111044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
111144d362409d5469aed47d19e7908d19bd194493aThomas Graf
111244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
111344d362409d5469aed47d19e7908d19bd194493aThomas Graf
111444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
111544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Link Flags Translations
111644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
111744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
111844d362409d5469aed47d19e7908d19bd194493aThomas Graf
111944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct trans_tbl link_flags[] = {
112044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_LOOPBACK, loopback)
112144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_BROADCAST, broadcast)
112244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_POINTOPOINT, pointopoint)
112344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_MULTICAST, multicast)
112444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_NOARP, noarp)
112544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_ALLMULTI, allmulti)
112644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_PROMISC, promisc)
112744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_MASTER, master)
112844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_SLAVE, slave)
112944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_DEBUG, debug)
113044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_DYNAMIC, dynamic)
113144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_AUTOMEDIA, automedia)
113244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_PORTSEL, portsel)
113344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_NOTRAILERS, notrailers)
113444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_UP, up)
113544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_RUNNING, running)
113644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_LOWER_UP, lowerup)
113744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(IFF_DORMANT, dormant)
1138195241473723527e2f30ac120087f106c607ce3eThomas Graf	__ADD(IFF_ECHO, echo)
113944d362409d5469aed47d19e7908d19bd194493aThomas Graf};
114044d362409d5469aed47d19e7908d19bd194493aThomas Graf
114144d362409d5469aed47d19e7908d19bd194493aThomas Grafchar * rtnl_link_flags2str(int flags, char *buf, size_t len)
114244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
114344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __flags2str(flags, buf, len, link_flags,
114444d362409d5469aed47d19e7908d19bd194493aThomas Graf			   ARRAY_SIZE(link_flags));
114544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
114644d362409d5469aed47d19e7908d19bd194493aThomas Graf
114744d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_link_str2flags(const char *name)
114844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
114944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
115044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
115144d362409d5469aed47d19e7908d19bd194493aThomas Graf
115244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
115344d362409d5469aed47d19e7908d19bd194493aThomas Graf
115444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
115544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Link Statistics Translations
115644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
115744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
115844d362409d5469aed47d19e7908d19bd194493aThomas Graf
115944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct trans_tbl link_stats[] = {
116044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_PACKETS, rx_packets)
116144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_PACKETS, tx_packets)
116244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_BYTES, rx_bytes)
116344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_BYTES, tx_bytes)
116444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_ERRORS, rx_errors)
116544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_ERRORS, tx_errors)
116644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
116744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
116844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
116944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
117044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
117144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
117244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
117344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
117444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
117544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
117644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
117744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
117844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
117944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
118044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
118144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_TX_COLLISIONS, tx_collision)
118244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(RTNL_LINK_MULTICAST, multicast)
118344d362409d5469aed47d19e7908d19bd194493aThomas Graf};
118444d362409d5469aed47d19e7908d19bd194493aThomas Graf
118544d362409d5469aed47d19e7908d19bd194493aThomas Grafchar *rtnl_link_stat2str(int st, char *buf, size_t len)
118644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
118744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
118844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
118944d362409d5469aed47d19e7908d19bd194493aThomas Graf
119044d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_link_str2stat(const char *name)
119144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
119244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
119344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
119444d362409d5469aed47d19e7908d19bd194493aThomas Graf
119544d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
119644d362409d5469aed47d19e7908d19bd194493aThomas Graf
119744d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
11983ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf * @name Link Operstate Translations
11993ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf * @{
12003ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf */
12013ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
12023ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafstatic struct trans_tbl link_operstates[] = {
12033ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_OPER_UNKNOWN, unknown)
12043ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_OPER_NOTPRESENT, notpresent)
12053ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_OPER_DOWN, down)
12063ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
12073ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_OPER_TESTING, testing)
12083ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_OPER_DORMANT, dormant)
12093ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_OPER_UP, up)
12103ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf};
12113ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
12123ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafchar *rtnl_link_operstate2str(int st, char *buf, size_t len)
12133ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
12143ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	return __type2str(st, buf, len, link_operstates,
12153ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf			  ARRAY_SIZE(link_operstates));
12163ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
12173ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
12183ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafint rtnl_link_str2operstate(const char *name)
12193ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
12203ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	return __str2type(name, link_operstates,
12213ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf			  ARRAY_SIZE(link_operstates));
12223ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
12233ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
12243ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf/** @} */
12253ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
12263ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf/**
12273ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf * @name Link Mode Translations
12283ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf * @{
12293ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf */
12303ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
12313ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafstatic struct trans_tbl link_modes[] = {
12323ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_LINK_MODE_DEFAULT, default)
12333ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	__ADD(IF_LINK_MODE_DORMANT, dormant)
12343ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf};
12353ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
12363ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafchar *rtnl_link_mode2str(int st, char *buf, size_t len)
12373ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
12383ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
12393ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
12403ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
12413ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafint rtnl_link_str2mode(const char *name)
12423ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
12433ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
12443ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
12453ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
12463ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf/** @} */
12473ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
12483ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf/**
124944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Attributes
125044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
125144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
125244d362409d5469aed47d19e7908d19bd194493aThomas Graf
125344d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc)
125444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
125544d362409d5469aed47d19e7908d19bd194493aThomas Graf	strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1);
125644d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_QDISC;
125744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
125844d362409d5469aed47d19e7908d19bd194493aThomas Graf
125944d362409d5469aed47d19e7908d19bd194493aThomas Grafchar *rtnl_link_get_qdisc(struct rtnl_link *link)
126044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
126144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_QDISC)
126244d362409d5469aed47d19e7908d19bd194493aThomas Graf		return link->l_qdisc;
126344d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
126444d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
126544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
126644d362409d5469aed47d19e7908d19bd194493aThomas Graf
126744d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_name(struct rtnl_link *link, const char *name)
126844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
126944d362409d5469aed47d19e7908d19bd194493aThomas Graf	strncpy(link->l_name, name, sizeof(link->l_name) - 1);
127044d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_IFNAME;
127144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
127244d362409d5469aed47d19e7908d19bd194493aThomas Graf
127344d362409d5469aed47d19e7908d19bd194493aThomas Grafchar *rtnl_link_get_name(struct rtnl_link *link)
127444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
127544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_IFNAME)
127644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return link->l_name;
127744d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
127844d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
127944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
128044d362409d5469aed47d19e7908d19bd194493aThomas Graf
128144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
128244d362409d5469aed47d19e7908d19bd194493aThomas Graf				 struct nl_addr *new, int flag)
128344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
128444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (*pos)
128544d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_put(*pos);
128644d362409d5469aed47d19e7908d19bd194493aThomas Graf
128744d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_get(new);
128844d362409d5469aed47d19e7908d19bd194493aThomas Graf	*pos = new;
128944d362409d5469aed47d19e7908d19bd194493aThomas Graf
129044d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= flag;
129144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
129244d362409d5469aed47d19e7908d19bd194493aThomas Graf
129344d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
129444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
129544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
129644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
129744d362409d5469aed47d19e7908d19bd194493aThomas Graf
129844d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
129944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
130044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_ADDR)
130144d362409d5469aed47d19e7908d19bd194493aThomas Graf		return link->l_addr;
130244d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
130344d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
130444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
130544d362409d5469aed47d19e7908d19bd194493aThomas Graf
130644d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd)
130744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
130844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD);
130944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
131044d362409d5469aed47d19e7908d19bd194493aThomas Graf
131144d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
131244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
131344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_BRD)
131444d362409d5469aed47d19e7908d19bd194493aThomas Graf		return link->l_bcast;
131544d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
131644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
131744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
131844d362409d5469aed47d19e7908d19bd194493aThomas Graf
131944d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
132044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
132144d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_flag_mask |= flags;
132244d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_flags |= flags;
132344d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_FLAGS;
132444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
132544d362409d5469aed47d19e7908d19bd194493aThomas Graf
132644d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
132744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
132844d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_flag_mask |= flags;
132944d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_flags &= ~flags;
133044d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_FLAGS;
133144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
133244d362409d5469aed47d19e7908d19bd194493aThomas Graf
133344d362409d5469aed47d19e7908d19bd194493aThomas Grafunsigned int rtnl_link_get_flags(struct rtnl_link *link)
133444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
133544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return link->l_flags;
133644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
133744d362409d5469aed47d19e7908d19bd194493aThomas Graf
133844d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_family(struct rtnl_link *link, int family)
133944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
134044d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_family = family;
134144d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_FAMILY;
134244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
134344d362409d5469aed47d19e7908d19bd194493aThomas Graf
134444d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_link_get_family(struct rtnl_link *link)
134544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
134644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->l_family & LINK_ATTR_FAMILY)
134744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return link->l_family;
134844d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
134944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return AF_UNSPEC;
135044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
135144d362409d5469aed47d19e7908d19bd194493aThomas Graf
135244d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
135344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
135444d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_arptype = arptype;
135544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
135644d362409d5469aed47d19e7908d19bd194493aThomas Graf
135744d362409d5469aed47d19e7908d19bd194493aThomas Grafunsigned int rtnl_link_get_arptype(struct rtnl_link *link)
135844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
135944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return link->l_arptype;
136044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
136144d362409d5469aed47d19e7908d19bd194493aThomas Graf
136244d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
136344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
136444d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_index = ifindex;
136544d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_IFINDEX;
136644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
136744d362409d5469aed47d19e7908d19bd194493aThomas Graf
136844d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_link_get_ifindex(struct rtnl_link *link)
136944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
1370b4fbe1d34d6f54045b5c6236d86aacd4340ec83dThomas Graf	return link->l_index;
137144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
137244d362409d5469aed47d19e7908d19bd194493aThomas Graf
137344d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
137444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
137544d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_mtu = mtu;
137644d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_MTU;
137744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
137844d362409d5469aed47d19e7908d19bd194493aThomas Graf
137944d362409d5469aed47d19e7908d19bd194493aThomas Grafunsigned int rtnl_link_get_mtu(struct rtnl_link *link)
138044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
138144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_MTU)
138244d362409d5469aed47d19e7908d19bd194493aThomas Graf		return link->l_mtu;
138344d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
138444d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 0;
138544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
138644d362409d5469aed47d19e7908d19bd194493aThomas Graf
138744d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
138844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
138944d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_txqlen = txqlen;
139044d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_TXQLEN;
139144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
139244d362409d5469aed47d19e7908d19bd194493aThomas Graf
139344d362409d5469aed47d19e7908d19bd194493aThomas Grafunsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
139444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
139544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_TXQLEN)
139644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return link->l_txqlen;
139744d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
139844d362409d5469aed47d19e7908d19bd194493aThomas Graf		return UINT_MAX;
139944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
140044d362409d5469aed47d19e7908d19bd194493aThomas Graf
140144d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
140244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
140344d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_weight = weight;
140444d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_WEIGHT;
140544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
140644d362409d5469aed47d19e7908d19bd194493aThomas Graf
140744d362409d5469aed47d19e7908d19bd194493aThomas Grafunsigned int rtnl_link_get_weight(struct rtnl_link *link)
140844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
140944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link->ce_mask & LINK_ATTR_WEIGHT)
141044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return link->l_weight;
141144d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
141244d362409d5469aed47d19e7908d19bd194493aThomas Graf		return UINT_MAX;
141344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
141444d362409d5469aed47d19e7908d19bd194493aThomas Graf
141544d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_link(struct rtnl_link *link, int ifindex)
141644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
141744d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_link = ifindex;
141844d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_LINK;
141944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
142044d362409d5469aed47d19e7908d19bd194493aThomas Graf
142144d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_link_get_link(struct rtnl_link *link)
142244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
1423b4fbe1d34d6f54045b5c6236d86aacd4340ec83dThomas Graf	return link->l_link;
142444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
142544d362409d5469aed47d19e7908d19bd194493aThomas Graf
142644d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_link_set_master(struct rtnl_link *link, int ifindex)
142744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
142844d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->l_master = ifindex;
142944d362409d5469aed47d19e7908d19bd194493aThomas Graf	link->ce_mask |= LINK_ATTR_MASTER;
143044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
143144d362409d5469aed47d19e7908d19bd194493aThomas Graf
143244d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_link_get_master(struct rtnl_link *link)
143344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
1434b4fbe1d34d6f54045b5c6236d86aacd4340ec83dThomas Graf	return link->l_master;
143544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
143644d362409d5469aed47d19e7908d19bd194493aThomas Graf
14373ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafvoid rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate)
14383ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
14393ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	link->l_operstate = operstate;
14403ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	link->ce_mask |= LINK_ATTR_OPERSTATE;
14413ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
14423ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
14433ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafuint8_t rtnl_link_get_operstate(struct rtnl_link *link)
14443ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
14453ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	if (link->ce_mask & LINK_ATTR_OPERSTATE)
14463ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		return link->l_operstate;
14473ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	else
14483ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		return IF_OPER_UNKNOWN;
14493ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
14503ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
14513ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafvoid rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t linkmode)
14523ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
14533ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	link->l_linkmode = linkmode;
14543ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	link->ce_mask |= LINK_ATTR_LINKMODE;
14553ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
14563ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
14573ad4665be2f192291238cbe78118a57ec42436c6Thomas Grafuint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
14583ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf{
14593ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	if (link->ce_mask & LINK_ATTR_LINKMODE)
14603ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		return link->l_linkmode;
14613ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf	else
14623ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf		return IF_LINK_MODE_DEFAULT;
14633ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf}
14643ad4665be2f192291238cbe78118a57ec42436c6Thomas Graf
146544d362409d5469aed47d19e7908d19bd194493aThomas Grafuint64_t rtnl_link_get_stat(struct rtnl_link *link, int id)
146644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
146744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (id < 0 || id > RTNL_LINK_STATS_MAX)
146844d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 0;
146944d362409d5469aed47d19e7908d19bd194493aThomas Graf
147044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return link->l_stats[id];
147144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
147244d362409d5469aed47d19e7908d19bd194493aThomas Graf
1473a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf/**
1474a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * Specify the info type of a link
1475a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * @arg link	link object
1476a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * @arg type	info type
1477a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf *
1478a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * Looks up the info type and prepares the link to store info type
1479a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * specific attributes. If an info type has been assigned already
1480a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * it will be released with all changes lost.
1481a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf *
1482a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * @return 0 on success or a negative errror code.
1483a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf */
1484a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Grafint rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
1485a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf{
1486a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	struct rtnl_link_info_ops *io;
1487a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	int err;
1488a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
1489a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if ((io = rtnl_link_info_ops_lookup(type)) == NULL)
14908a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_OPNOTSUPP;
1491a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
1492a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if (link->l_info_ops)
1493a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		release_link_info(link);
1494a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
1495a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if ((err = io->io_alloc(link)) < 0)
1496a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		return err;
1497a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
1498a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	link->l_info_ops = io;
1499a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
1500a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	return 0;
1501a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf}
1502a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
1503a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf/**
1504a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * Return info type of a link
1505a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * @arg link	link object
1506a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf *
1507a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * @note The returned pointer is only valid as long as the link exists
1508a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf * @return Info type name or NULL if unknown.
1509a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf */
1510a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Grafchar *rtnl_link_get_info_type(struct rtnl_link *link)
1511a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf{
1512a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	if (link->l_info_ops)
1513a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		return link->l_info_ops->io_name;
1514a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf	else
1515a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf		return NULL;
1516a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf}
1517a7469ce758fac3631df6ce72eb3f89150070e7f8Thomas Graf
151844d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
151944d362409d5469aed47d19e7908d19bd194493aThomas Graf
152044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_object_ops link_obj_ops = {
152144d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_name		= "route/link",
152244d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_size		= sizeof(struct rtnl_link),
152344d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_free_data		= link_free_data,
152444d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_clone		= link_clone,
152544d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_dump[NL_DUMP_BRIEF]	= link_dump_brief,
152644d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_dump[NL_DUMP_FULL]	= link_dump_full,
152744d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_dump[NL_DUMP_STATS]	= link_dump_stats,
152844d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_dump[NL_DUMP_XML]	= link_dump_xml,
152944d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_dump[NL_DUMP_ENV]	= link_dump_env,
153044d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_compare		= link_compare,
153144d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_attrs2str		= link_attrs2str,
153244d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_id_attrs		= LINK_ATTR_IFINDEX,
153344d362409d5469aed47d19e7908d19bd194493aThomas Graf};
153444d362409d5469aed47d19e7908d19bd194493aThomas Graf
153544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_af_group link_groups[] = {
153644d362409d5469aed47d19e7908d19bd194493aThomas Graf	{ AF_UNSPEC,	RTNLGRP_LINK },
153744d362409d5469aed47d19e7908d19bd194493aThomas Graf	{ END_OF_GROUP_LIST },
153844d362409d5469aed47d19e7908d19bd194493aThomas Graf};
153944d362409d5469aed47d19e7908d19bd194493aThomas Graf
154044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_cache_ops rtnl_link_ops = {
154144d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_name		= "route/link",
154244d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_hdrsize		= sizeof(struct ifinfomsg),
154344d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_msgtypes		= {
154444d362409d5469aed47d19e7908d19bd194493aThomas Graf					{ RTM_NEWLINK, NL_ACT_NEW, "new" },
154544d362409d5469aed47d19e7908d19bd194493aThomas Graf					{ RTM_DELLINK, NL_ACT_DEL, "del" },
154644d362409d5469aed47d19e7908d19bd194493aThomas Graf					{ RTM_GETLINK, NL_ACT_GET, "get" },
154744d362409d5469aed47d19e7908d19bd194493aThomas Graf					END_OF_MSGTYPES_LIST,
154844d362409d5469aed47d19e7908d19bd194493aThomas Graf				  },
154944d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_protocol		= NETLINK_ROUTE,
155044d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_groups		= link_groups,
155144d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_request_update	= link_request_update,
155244d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_msg_parser		= link_msg_parser,
155344d362409d5469aed47d19e7908d19bd194493aThomas Graf	.co_obj_ops		= &link_obj_ops,
155444d362409d5469aed47d19e7908d19bd194493aThomas Graf};
155544d362409d5469aed47d19e7908d19bd194493aThomas Graf
155644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void __init link_init(void)
155744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
155844d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_cache_mngt_register(&rtnl_link_ops);
155944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
156044d362409d5469aed47d19e7908d19bd194493aThomas Graf
156144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void __exit link_exit(void)
156244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
156344d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_cache_mngt_unregister(&rtnl_link_ops);
156444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
156544d362409d5469aed47d19e7908d19bd194493aThomas Graf
156644d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
1567