link.c revision 1155370f520cb64657e25153255cf7dc1424317f
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/*
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * lib/route/link.c	Links (Interfaces)
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *	This library is free software; you can redistribute it and/or
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *	modify it under the terms of the GNU Lesser General Public
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *	License as published by the Free Software Foundation version 2.1
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *	of the License.
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
10a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) */
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @ingroup rtnl
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @defgroup link Links (Interfaces)
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @brief
16ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @par Link Identification
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * A link can be identified by either its interface index or by its
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * name. The kernel favours the interface index but falls back to the
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * interface name if the interface index is lesser-than 0 for kernels
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * >= 2.6.11. Therefore you can request changes without mapping a
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * interface name to the corresponding index first.
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @par Changeable Attributes
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @anchor link_changeable
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *  - Link layer address
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *  - Link layer broadcast address
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *  - device mapping (ifmap) (>= 2.6.9)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *  - MTU (>= 2.6.9)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *  - Transmission queue length (>= 2.6.9)
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *  - Weight (>= 2.6.9)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *  - Link name (only via access through interface index) (>= 2.6.9)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *  - Flags (>= 2.6.9)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *    - IFF_DEBUG
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *    - IFF_NOTRAILERS
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *    - IFF_NOARP
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *    - IFF_DYNAMIC
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *    - IFF_MULTICAST
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *    - IFF_PORTSEL
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *    - IFF_AUTOMEDIA
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *    - IFF_UP
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *    - IFF_PROMISC
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *    - IFF_ALLMULTI
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @par Link Flags (linux/if.h)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @anchor link_flags
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @code
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *   IFF_UP            Status of link (up|down)
49ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *   IFF_BROADCAST     Indicates this link allows broadcasting
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *   IFF_MULTICAST     Indicates this link allows multicasting
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *   IFF_ALLMULTI      Indicates this link is doing multicast routing
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *   IFF_DEBUG         Tell the driver to do debugging (currently unused)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *   IFF_LOOPBACK      This is the loopback link
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *   IFF_POINTOPOINT   Point-to-point link
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *   IFF_NOARP         Link is unable to perform ARP
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *   IFF_PROMISC       Status of promiscious mode flag
577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) *   IFF_MASTER        Used by teql
587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) *   IFF_SLAVE         Used by teql
59ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *   IFF_PORTSEL       Indicates this link allows port selection
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *   IFF_AUTOMEDIA     Indicates this link selects port automatically
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *   IFF_DYNAMIC       Indicates the address of this link is dynamic
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *   IFF_RUNNING       Link is running and carrier is ok.
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *   IFF_NOTRAILERS    Unused, BSD compat.
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @endcode
65ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *
66a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * @par Notes on IFF_PROMISC and IFF_ALLMULTI flags
67a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * Although you can query the status of IFF_PROMISC and IFF_ALLMULTI
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * they do not represent the actual state in the kernel but rather
69a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * whether the flag has been enabled/disabled by userspace. The link
70a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * may be in promiscious mode even if IFF_PROMISC is not set in a link
71a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * dump request response because promiscity might be needed by the driver
72a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * for a period of time.
73a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch *
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @note The unit of the transmission queue length depends on the
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *       link type, a common unit is \a packets.
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @par 1) Retrieving information about available links
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @code
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * // The first step is to retrieve a list of all available interfaces within
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * // the kernel and put them into a cache.
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * struct nl_cache *cache = rtnl_link_alloc_cache(sk);
827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) *
837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) * // In a second step, a specific link may be looked up by either interface
84a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * // index or interface name.
85a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * struct rtnl_link *link = rtnl_link_get_by_name(cache, "lo");
86a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch *
87ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * // rtnl_link_get_by_name() is the short version for translating the
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * // interface name to an interface index first like this:
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * int ifindex = rtnl_link_name2i(cache, "lo");
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * struct rtnl_link *link = rtnl_link_get(cache, ifindex);
91a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch *
92a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * // After successful usage, the object must be given back to the cache
93a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * rtnl_link_put(link);
94a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * @endcode
95a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch *
96a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * @par 2) Changing link attributes
97a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * @code
98a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * // In order to change any attributes of an existing link, we must allocate
99a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * // a new link to hold the change requests:
100a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * struct rtnl_link *request = rtnl_link_alloc();
101a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch *
102a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * // Now we can go on and specify the attributes we want to change:
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * rtnl_link_set_weight(request, 300);
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * rtnl_link_set_mtu(request, 1360);
1057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) *
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * // We can also shut an interface down administratively
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * rtnl_link_unset_flags(request, rtnl_link_str2flags("up"));
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * // Actually, we should know which link to change, so let's look it up
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * struct rtnl_link *old = rtnl_link_get(cache, "eth0");
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
1127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) * // Two ways exist to commit this change request, the first one is to
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * // build the required netlink message and send it out in one single
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * // step:
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * rtnl_link_change(sk, old, request);
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * // An alternative way is to build the netlink message and send it
1187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) * // out yourself using nl_send_auto_complete()
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * struct nl_msg *msg = rtnl_link_build_change_request(old, request);
120ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * nl_send_auto_complete(sk, nlmsg_hdr(msg));
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * nlmsg_free(msg);
122a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * // Don't forget to give back the link object ;->
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * rtnl_link_put(old);
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @endcode
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @par 3) Link Type Specific Attributes
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @code
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * // Some link types offer additional parameters and statistics specific
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * // to their type. F.e. a VLAN link can be configured like this:
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * //
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * // Allocate a new link and set the info type to "vlan". This is required
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * // to prepare the link to hold vlan specific attributes.
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * struct rtnl_link *request = rtnl_link_alloc();
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * rtnl_link_set_info_type(request, "vlan");
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * // Now vlan specific attributes can be set:
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * rtnl_link_vlan_set_id(request, 10);
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * rtnl_link_vlan_set_ingress_map(request, 2, 8);
140a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * // Of course the attributes can also be read, check the info type
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * // to make sure you are using the right access functions:
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * char *type = rtnl_link_get_info_type(link);
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * if (!strcmp(type, "vlan"))
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 	int id = rtnl_link_vlan_get_id(link);
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @endcode
1477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) * @{
1487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) */
149ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <netlink-local.h>
15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <netlink/netlink.h>
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <netlink/attr.h>
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <netlink/utils.h>
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <netlink/object.h>
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <netlink/route/rtnl.h>
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <netlink/route/link.h>
157ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include <netlink/route/link/info-api.h>
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
159a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)/** @cond SKIP */
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_MTU     0x0001
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_LINK    0x0002
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_TXQLEN  0x0004
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_WEIGHT  0x0008
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_MASTER  0x0010
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_QDISC   0x0020
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_MAP     0x0040
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_ADDR    0x0080
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_BRD     0x0100
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_FLAGS   0x0200
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_IFNAME  0x0400
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_IFINDEX 0x0800
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_FAMILY  0x1000
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_ARPTYPE 0x2000
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_STATS   0x4000
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_CHANGE  0x8000
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define LINK_ATTR_OPERSTATE 0x10000
1777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#define LINK_ATTR_LINKMODE  0x20000
1787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#define LINK_ATTR_LINKINFO  0x40000
179ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static struct nl_cache_ops rtnl_link_ops;
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static struct nl_object_ops link_obj_ops;
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** @endcond */
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static void release_link_info(struct rtnl_link *link)
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
186ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct rtnl_link_info_ops *io = link->l_info_ops;
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
188a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	if (io != NULL) {
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		io->io_refcnt--;
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		io->io_free(link);
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		link->l_info_ops = NULL;
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	}
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static void link_free_data(struct nl_object *c)
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	struct rtnl_link *link = nl_object_priv(c);
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	if (link) {
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		struct rtnl_link_info_ops *io;
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
202a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)		if ((io = link->l_info_ops) != NULL)
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			release_link_info(link);
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)		nl_addr_put(link->l_addr);
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		nl_addr_put(link->l_bcast);
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	}
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
20990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
21090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)static int link_clone(struct nl_object *_dst, struct nl_object *_src)
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	struct rtnl_link *dst = nl_object_priv(_dst);
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	struct rtnl_link *src = nl_object_priv(_src);
2147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	int err;
2157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
216ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (src->l_addr)
217a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)		if (!(dst->l_addr = nl_addr_clone(src->l_addr)))
218a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)			return -NLE_NOMEM;
219a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
220a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	if (src->l_bcast)
221a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)		if (!(dst->l_bcast = nl_addr_clone(src->l_bcast)))
222a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)			return -NLE_NOMEM;
223a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
224a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	if (src->l_info_ops && src->l_info_ops->io_clone) {
225a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)		err = src->l_info_ops->io_clone(dst, src);
226a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)		if (err < 0)
227a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)			return err;
228a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	}
229a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
230a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	return 0;
231a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
232a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
233a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)static struct nla_policy link_policy[IFLA_MAX+1] = {
234a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	[IFLA_IFNAME]	= { .type = NLA_STRING,
235a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)			    .maxlen = IFNAMSIZ },
236a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	[IFLA_MTU]	= { .type = NLA_U32 },
237a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	[IFLA_TXQLEN]	= { .type = NLA_U32 },
238a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	[IFLA_LINK]	= { .type = NLA_U32 },
239a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	[IFLA_WEIGHT]	= { .type = NLA_U32 },
240a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	[IFLA_MASTER]	= { .type = NLA_U32 },
241a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	[IFLA_OPERSTATE]= { .type = NLA_U8 },
242a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	[IFLA_LINKMODE] = { .type = NLA_U8 },
243a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	[IFLA_LINKINFO]	= { .type = NLA_NESTED },
244a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	[IFLA_QDISC]	= { .type = NLA_STRING,
245a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)			    .maxlen = IFQDISCSIZ },
246a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	[IFLA_STATS]	= { .minlen = sizeof(struct rtnl_link_stats) },
247a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	[IFLA_MAP]	= { .minlen = sizeof(struct rtnl_link_ifmap) },
248a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)};
249a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
250a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
251a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	[IFLA_INFO_KIND]	= { .type = NLA_STRING },
252a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	[IFLA_INFO_DATA]	= { .type = NLA_NESTED },
253	[IFLA_INFO_XSTATS]	= { .type = NLA_NESTED },
254};
255
256static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
257			   struct nlmsghdr *n, struct nl_parser_param *pp)
258{
259	struct rtnl_link *link;
260	struct ifinfomsg *ifi;
261	struct nlattr *tb[IFLA_MAX+1];
262	int err;
263
264	link = rtnl_link_alloc();
265	if (link == NULL) {
266		err = -NLE_NOMEM;
267		goto errout;
268	}
269
270	link->ce_msgtype = n->nlmsg_type;
271
272	err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy);
273	if (err < 0)
274		goto errout;
275
276	if (tb[IFLA_IFNAME] == NULL) {
277		err = -NLE_MISSING_ATTR;
278		goto errout;
279	}
280
281	nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
282
283	ifi = nlmsg_data(n);
284	link->l_family = ifi->ifi_family;
285	link->l_arptype = ifi->ifi_type;
286	link->l_index = ifi->ifi_index;
287	link->l_flags = ifi->ifi_flags;
288	link->l_change = ifi->ifi_change;
289	link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
290			  LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
291			  LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
292
293	if (tb[IFLA_STATS]) {
294		struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
295
296		link->l_stats[RTNL_LINK_RX_PACKETS]	= st->rx_packets;
297		link->l_stats[RTNL_LINK_RX_BYTES]	= st->rx_bytes;
298		link->l_stats[RTNL_LINK_RX_ERRORS]	= st->rx_errors;
299		link->l_stats[RTNL_LINK_RX_DROPPED]	= st->rx_dropped;
300		link->l_stats[RTNL_LINK_RX_COMPRESSED]	= st->rx_compressed;
301		link->l_stats[RTNL_LINK_RX_FIFO_ERR]	= st->rx_fifo_errors;
302		link->l_stats[RTNL_LINK_TX_PACKETS]	= st->tx_packets;
303		link->l_stats[RTNL_LINK_TX_BYTES]	= st->tx_bytes;
304		link->l_stats[RTNL_LINK_TX_ERRORS]	= st->tx_errors;
305		link->l_stats[RTNL_LINK_TX_DROPPED]	= st->tx_dropped;
306		link->l_stats[RTNL_LINK_TX_COMPRESSED]	= st->tx_compressed;
307		link->l_stats[RTNL_LINK_TX_FIFO_ERR]	= st->tx_fifo_errors;
308		link->l_stats[RTNL_LINK_RX_LEN_ERR]	= st->rx_length_errors;
309		link->l_stats[RTNL_LINK_RX_OVER_ERR]	= st->rx_over_errors;
310		link->l_stats[RTNL_LINK_RX_CRC_ERR]	= st->rx_crc_errors;
311		link->l_stats[RTNL_LINK_RX_FRAME_ERR]	= st->rx_frame_errors;
312		link->l_stats[RTNL_LINK_RX_MISSED_ERR]	= st->rx_missed_errors;
313		link->l_stats[RTNL_LINK_TX_ABORT_ERR]	= st->tx_aborted_errors;
314		link->l_stats[RTNL_LINK_TX_CARRIER_ERR]	= st->tx_carrier_errors;
315		link->l_stats[RTNL_LINK_TX_HBEAT_ERR]	= st->tx_heartbeat_errors;
316		link->l_stats[RTNL_LINK_TX_WIN_ERR]	= st->tx_window_errors;
317		link->l_stats[RTNL_LINK_MULTICAST]	= st->multicast;
318
319		link->ce_mask |= LINK_ATTR_STATS;
320	}
321
322	if (tb[IFLA_TXQLEN]) {
323		link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]);
324		link->ce_mask |= LINK_ATTR_TXQLEN;
325	}
326
327	if (tb[IFLA_MTU]) {
328		link->l_mtu = nla_get_u32(tb[IFLA_MTU]);
329		link->ce_mask |= LINK_ATTR_MTU;
330	}
331
332	if (tb[IFLA_ADDRESS]) {
333		link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC);
334		if (link->l_addr == NULL) {
335			err = -NLE_NOMEM;
336			goto errout;
337		}
338		nl_addr_set_family(link->l_addr,
339				   nl_addr_guess_family(link->l_addr));
340		link->ce_mask |= LINK_ATTR_ADDR;
341	}
342
343	if (tb[IFLA_BROADCAST]) {
344		link->l_bcast = nl_addr_alloc_attr(tb[IFLA_BROADCAST],
345						   AF_UNSPEC);
346		if (link->l_bcast == NULL) {
347			err = -NLE_NOMEM;
348			goto errout;
349		}
350		nl_addr_set_family(link->l_bcast,
351				   nl_addr_guess_family(link->l_bcast));
352		link->ce_mask |= LINK_ATTR_BRD;
353	}
354
355	if (tb[IFLA_LINK]) {
356		link->l_link = nla_get_u32(tb[IFLA_LINK]);
357		link->ce_mask |= LINK_ATTR_LINK;
358	}
359
360	if (tb[IFLA_WEIGHT]) {
361		link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]);
362		link->ce_mask |= LINK_ATTR_WEIGHT;
363	}
364
365	if (tb[IFLA_QDISC]) {
366		nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
367		link->ce_mask |= LINK_ATTR_QDISC;
368	}
369
370	if (tb[IFLA_MAP]) {
371		nla_memcpy(&link->l_map, tb[IFLA_MAP],
372			   sizeof(struct rtnl_link_ifmap));
373		link->ce_mask |= LINK_ATTR_MAP;
374	}
375
376	if (tb[IFLA_MASTER]) {
377		link->l_master = nla_get_u32(tb[IFLA_MASTER]);
378		link->ce_mask |= LINK_ATTR_MASTER;
379	}
380
381	if (tb[IFLA_OPERSTATE]) {
382		link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]);
383		link->ce_mask |= LINK_ATTR_OPERSTATE;
384	}
385
386	if (tb[IFLA_LINKMODE]) {
387		link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]);
388		link->ce_mask |= LINK_ATTR_LINKMODE;
389	}
390
391	if (tb[IFLA_LINKINFO]) {
392		struct nlattr *li[IFLA_INFO_MAX+1];
393
394		err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
395				       link_info_policy);
396		if (err < 0)
397			goto errout;
398
399		if (li[IFLA_INFO_KIND] &&
400		    (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
401			struct rtnl_link_info_ops *ops;
402			char *kind;
403
404			kind = nla_get_string(li[IFLA_INFO_KIND]);
405			ops = rtnl_link_info_ops_lookup(kind);
406			if (ops != NULL) {
407				ops->io_refcnt++;
408				link->l_info_ops = ops;
409				err = ops->io_parse(link, li[IFLA_INFO_DATA],
410						    li[IFLA_INFO_XSTATS]);
411				if (err < 0)
412					goto errout;
413			} else {
414				/* XXX: Warn about unparsed info? */
415			}
416		}
417	}
418
419	err = pp->pp_cb((struct nl_object *) link, pp);
420	if (err < 0)
421		goto errout;
422
423	err = P_ACCEPT;
424
425errout:
426	rtnl_link_put(link);
427	return err;
428}
429
430static int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
431{
432	return nl_rtgen_request(sk, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
433}
434
435static int link_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
436{
437	char buf[128];
438	struct nl_cache *cache = dp_cache(obj);
439	struct rtnl_link *link = (struct rtnl_link *) obj;
440	int line = 1;
441
442	dp_dump(p, "%s %s ", link->l_name,
443			     nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
444
445	if (link->l_addr && !nl_addr_iszero(link->l_addr))
446		dp_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
447
448	if (link->ce_mask & LINK_ATTR_MASTER) {
449		struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
450		dp_dump(p, "master %s ", master ? master->l_name : "inv");
451		if (master)
452			rtnl_link_put(master);
453	}
454
455	rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
456	if (buf[0])
457		dp_dump(p, "<%s> ", buf);
458
459	if (link->ce_mask & LINK_ATTR_LINK) {
460		struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
461		dp_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
462		if (ll)
463			rtnl_link_put(ll);
464	}
465
466	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_BRIEF])
467		line = link->l_info_ops->io_dump[NL_DUMP_BRIEF](link, p, line);
468
469	dp_dump(p, "\n");
470
471	return line;
472}
473
474static int link_dump_full(struct nl_object *obj, struct nl_dump_params *p)
475{
476	struct rtnl_link *link = (struct rtnl_link *) obj;
477	char buf[64];
478	int line;
479
480	line = link_dump_brief(obj, p);
481	dp_new_line(p, line++);
482
483	dp_dump(p, "    mtu %u ", link->l_mtu);
484	dp_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
485
486	if (link->ce_mask & LINK_ATTR_QDISC)
487		dp_dump(p, "qdisc %s ", link->l_qdisc);
488
489	if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
490		dp_dump(p, "irq %u ", link->l_map.lm_irq);
491
492	if (link->ce_mask & LINK_ATTR_IFINDEX)
493		dp_dump(p, "index %u ", link->l_index);
494
495
496	dp_dump(p, "\n");
497	dp_new_line(p, line++);
498
499	dp_dump(p, "    ");
500
501	if (link->ce_mask & LINK_ATTR_BRD)
502		dp_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
503						   sizeof(buf)));
504
505	if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
506	    link->l_operstate != IF_OPER_UNKNOWN) {
507		rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
508		dp_dump(p, "state %s ", buf);
509	}
510
511	dp_dump(p, "mode %s\n",
512		rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
513
514	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_FULL])
515		line = link->l_info_ops->io_dump[NL_DUMP_FULL](link, p, line);
516
517	return line;
518}
519
520static int link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
521{
522	struct rtnl_link *link = (struct rtnl_link *) obj;
523	char *unit, fmt[64];
524	float res;
525	int line;
526
527	line = link_dump_full(obj, p);
528
529	dp_dump_line(p, line++, "    Stats:    bytes    packets     errors "
530				"   dropped   fifo-err compressed\n");
531
532	res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
533
534	strcpy(fmt, "     RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
535	fmt[9] = *unit == 'B' ? '9' : '7';
536
537	dp_dump_line(p, line++, fmt,
538		res, unit,
539		link->l_stats[RTNL_LINK_RX_PACKETS],
540		link->l_stats[RTNL_LINK_RX_ERRORS],
541		link->l_stats[RTNL_LINK_RX_DROPPED],
542		link->l_stats[RTNL_LINK_RX_FIFO_ERR],
543		link->l_stats[RTNL_LINK_RX_COMPRESSED]);
544
545	res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
546
547	strcpy(fmt, "     TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
548	fmt[9] = *unit == 'B' ? '9' : '7';
549
550	dp_dump_line(p, line++, fmt,
551		res, unit,
552		link->l_stats[RTNL_LINK_TX_PACKETS],
553		link->l_stats[RTNL_LINK_TX_ERRORS],
554		link->l_stats[RTNL_LINK_TX_DROPPED],
555		link->l_stats[RTNL_LINK_TX_FIFO_ERR],
556		link->l_stats[RTNL_LINK_TX_COMPRESSED]);
557
558	dp_dump_line(p, line++, "    Errors:  length       over        crc "
559				"     frame     missed  multicast\n");
560
561	dp_dump_line(p, line++, "     RX  %10" PRIu64 " %10" PRIu64 " %10"
562				PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
563				PRIu64 "\n",
564		link->l_stats[RTNL_LINK_RX_LEN_ERR],
565		link->l_stats[RTNL_LINK_RX_OVER_ERR],
566		link->l_stats[RTNL_LINK_RX_CRC_ERR],
567		link->l_stats[RTNL_LINK_RX_FRAME_ERR],
568		link->l_stats[RTNL_LINK_RX_MISSED_ERR],
569		link->l_stats[RTNL_LINK_MULTICAST]);
570
571	dp_dump_line(p, line++, "            aborted    carrier  heartbeat "
572				"    window  collision\n");
573
574	dp_dump_line(p, line++, "     TX  %10" PRIu64 " %10" PRIu64 " %10"
575				PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
576		link->l_stats[RTNL_LINK_TX_ABORT_ERR],
577		link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
578		link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
579		link->l_stats[RTNL_LINK_TX_WIN_ERR],
580		link->l_stats[RTNL_LINK_TX_COLLISIONS]);
581
582	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
583		line = link->l_info_ops->io_dump[NL_DUMP_STATS](link, p, line);
584
585	return line;
586}
587
588static int link_dump_xml(struct nl_object *obj, struct nl_dump_params *p)
589{
590	struct rtnl_link *link = (struct rtnl_link *) obj;
591	struct nl_cache *cache = dp_cache(obj);
592	char buf[128];
593	int i, line = 0;
594
595	dp_dump_line(p, line++, "<link name=\"%s\" index=\"%u\">\n",
596		     link->l_name, link->l_index);
597	dp_dump_line(p, line++, "  <family>%s</family>\n",
598		     nl_af2str(link->l_family, buf, sizeof(buf)));
599	dp_dump_line(p, line++, "  <arptype>%s</arptype>\n",
600		     nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
601	dp_dump_line(p, line++, "  <address>%s</address>\n",
602		     nl_addr2str(link->l_addr, buf, sizeof(buf)));
603	dp_dump_line(p, line++, "  <mtu>%u</mtu>\n", link->l_mtu);
604	dp_dump_line(p, line++, "  <txqlen>%u</txqlen>\n", link->l_txqlen);
605	dp_dump_line(p, line++, "  <weight>%u</weight>\n", link->l_weight);
606
607	rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
608	if (buf[0])
609		dp_dump_line(p, line++, "  <flags>%s</flags>\n", buf);
610
611	if (link->ce_mask & LINK_ATTR_QDISC)
612		dp_dump_line(p, line++, "  <qdisc>%s</qdisc>\n", link->l_qdisc);
613
614	if (link->ce_mask & LINK_ATTR_LINK) {
615		struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
616		dp_dump_line(p, line++, "  <link>%s</link>\n",
617			     ll ? ll->l_name : "none");
618		if (ll)
619			rtnl_link_put(ll);
620	}
621
622	if (link->ce_mask & LINK_ATTR_MASTER) {
623		struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
624		dp_dump_line(p, line++, "  <master>%s</master>\n",
625			     master ? master->l_name : "none");
626		if (master)
627			rtnl_link_put(master);
628	}
629
630	if (link->ce_mask & LINK_ATTR_BRD)
631		dp_dump_line(p, line++, "  <broadcast>%s</broadcast>\n",
632			     nl_addr2str(link->l_bcast, buf, sizeof(buf)));
633
634	if (link->ce_mask & LINK_ATTR_STATS) {
635		dp_dump_line(p, line++, "  <stats>\n");
636		for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
637			rtnl_link_stat2str(i, buf, sizeof(buf));
638			dp_dump_line(p, line++,
639				     "    <%s>%" PRIu64 "</%s>\n",
640				     buf, link->l_stats[i], buf);
641		}
642		dp_dump_line(p, line++, "  </stats>\n");
643	}
644
645	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_XML]) {
646		dp_dump_line(p, line++, "  <info>\n");
647		line = link->l_info_ops->io_dump[NL_DUMP_XML](link, p, line);
648		dp_dump_line(p, line++, "  </info>\n");
649	}
650
651	dp_dump_line(p, line++, "</link>\n");
652
653#if 0
654	uint32_t	l_change;	/**< Change mask */
655	struct rtnl_lifmap l_map;	/**< Interface device mapping */
656#endif
657
658	return line;
659}
660
661static int link_dump_env(struct nl_object *obj, struct nl_dump_params *p)
662{
663	struct rtnl_link *link = (struct rtnl_link *) obj;
664	struct nl_cache *cache = dp_cache(obj);
665	char buf[128];
666	int i, line = 0;
667
668	dp_dump_line(p, line++, "LINK_NAME=%s\n", link->l_name);
669	dp_dump_line(p, line++, "LINK_IFINDEX=%u\n", link->l_index);
670	dp_dump_line(p, line++, "LINK_FAMILY=%s\n",
671		     nl_af2str(link->l_family, buf, sizeof(buf)));
672	dp_dump_line(p, line++, "LINK_TYPE=%s\n",
673		     nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
674	if (link->ce_mask & LINK_ATTR_ADDR)
675		dp_dump_line(p, line++, "LINK_ADDRESS=%s\n",
676			     nl_addr2str(link->l_addr, buf, sizeof(buf)));
677	dp_dump_line(p, line++, "LINK_MTU=%u\n", link->l_mtu);
678	dp_dump_line(p, line++, "LINK_TXQUEUELEN=%u\n", link->l_txqlen);
679	dp_dump_line(p, line++, "LINK_WEIGHT=%u\n", link->l_weight);
680
681	rtnl_link_flags2str(link->l_flags & ~IFF_RUNNING, buf, sizeof(buf));
682	if (buf[0])
683		dp_dump_line(p, line++, "LINK_FLAGS=%s\n", buf);
684
685	if (link->ce_mask & LINK_ATTR_QDISC)
686		dp_dump_line(p, line++, "LINK_QDISC=%s\n", link->l_qdisc);
687
688	if (link->ce_mask & LINK_ATTR_LINK) {
689		struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
690
691		dp_dump_line(p, line++, "LINK_LINK_IFINDEX=%d\n", link->l_link);
692		if (ll) {
693			dp_dump_line(p, line++, "LINK_LINK_IFNAME=%s\n",
694				     ll->l_name);
695			rtnl_link_put(ll);
696		}
697	}
698
699	if (link->ce_mask & LINK_ATTR_MASTER) {
700		struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
701		dp_dump_line(p, line++, "LINK_MASTER=%s\n",
702			     master ? master->l_name : "none");
703		if (master)
704			rtnl_link_put(master);
705	}
706
707	if (link->ce_mask & LINK_ATTR_BRD)
708		dp_dump_line(p, line++, "LINK_BROADCAST=%s\n",
709			     nl_addr2str(link->l_bcast, buf, sizeof(buf)));
710
711	if (link->ce_mask & LINK_ATTR_STATS) {
712		for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
713			char *c = buf;
714
715			sprintf(buf, "LINK_");
716			rtnl_link_stat2str(i, buf + 5, sizeof(buf) - 5);
717			while (*c) {
718				*c = toupper(*c);
719				c++;
720			}
721			dp_dump_line(p, line++,
722				     "%s=%" PRIu64 "\n", buf, link->l_stats[i]);
723		}
724	}
725
726	if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_ENV])
727		line = link->l_info_ops->io_dump[NL_DUMP_ENV](link, p, line);
728
729	return line;
730}
731
732#if 0
733static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
734{
735	struct rtnl_link *l = (struct rtnl_link *) a;
736	struct nl_cache *c = dp_cache(a);
737	int nevents = 0;
738
739	if (l->l_change == ~0U) {
740		if (l->ce_msgtype == RTM_NEWLINK)
741			cb->le_register(l);
742		else
743			cb->le_unregister(l);
744
745		return 1;
746	}
747
748	if (l->l_change & IFF_SLAVE) {
749		if (l->l_flags & IFF_SLAVE) {
750			struct rtnl_link *m = rtnl_link_get(c, l->l_master);
751			cb->le_new_bonding(l, m);
752			if (m)
753				rtnl_link_put(m);
754		} else
755			cb->le_cancel_bonding(l);
756	}
757
758#if 0
759	if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
760		dp_dump_line(p, line++, "link %s changed state to %s.\n",
761			l->l_name, l->l_flags & IFF_UP ? "up" : "down");
762
763	if (l->l_change & IFF_PROMISC) {
764		dp_new_line(p, line++);
765		dp_dump(p, "link %s %s promiscuous mode.\n",
766		    l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
767	}
768
769	if (line == 0)
770		dp_dump_line(p, line++, "link %s sent unknown event.\n",
771			     l->l_name);
772#endif
773
774	return nevents;
775}
776#endif
777
778static int link_compare(struct nl_object *_a, struct nl_object *_b,
779			uint32_t attrs, int flags)
780{
781	struct rtnl_link *a = (struct rtnl_link *) _a;
782	struct rtnl_link *b = (struct rtnl_link *) _b;
783	int diff = 0;
784
785#define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
786
787	diff |= LINK_DIFF(IFINDEX,	a->l_index != b->l_index);
788	diff |= LINK_DIFF(MTU,		a->l_mtu != b->l_mtu);
789	diff |= LINK_DIFF(LINK,		a->l_link != b->l_link);
790	diff |= LINK_DIFF(TXQLEN,	a->l_txqlen != b->l_txqlen);
791	diff |= LINK_DIFF(WEIGHT,	a->l_weight != b->l_weight);
792	diff |= LINK_DIFF(MASTER,	a->l_master != b->l_master);
793	diff |= LINK_DIFF(FAMILY,	a->l_family != b->l_family);
794	diff |= LINK_DIFF(OPERSTATE,	a->l_operstate != b->l_operstate);
795	diff |= LINK_DIFF(LINKMODE,	a->l_linkmode != b->l_linkmode);
796	diff |= LINK_DIFF(QDISC,	strcmp(a->l_qdisc, b->l_qdisc));
797	diff |= LINK_DIFF(IFNAME,	strcmp(a->l_name, b->l_name));
798	diff |= LINK_DIFF(ADDR,		nl_addr_cmp(a->l_addr, b->l_addr));
799	diff |= LINK_DIFF(BRD,		nl_addr_cmp(a->l_bcast, b->l_bcast));
800
801	if (flags & LOOSE_COMPARISON)
802		diff |= LINK_DIFF(FLAGS,
803				  (a->l_flags ^ b->l_flags) & b->l_flag_mask);
804	else
805		diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
806
807#undef LINK_DIFF
808
809	return diff;
810}
811
812static struct trans_tbl link_attrs[] = {
813	__ADD(LINK_ATTR_MTU, mtu)
814	__ADD(LINK_ATTR_LINK, link)
815	__ADD(LINK_ATTR_TXQLEN, txqlen)
816	__ADD(LINK_ATTR_WEIGHT, weight)
817	__ADD(LINK_ATTR_MASTER, master)
818	__ADD(LINK_ATTR_QDISC, qdisc)
819	__ADD(LINK_ATTR_MAP, map)
820	__ADD(LINK_ATTR_ADDR, address)
821	__ADD(LINK_ATTR_BRD, broadcast)
822	__ADD(LINK_ATTR_FLAGS, flags)
823	__ADD(LINK_ATTR_IFNAME, name)
824	__ADD(LINK_ATTR_IFINDEX, ifindex)
825	__ADD(LINK_ATTR_FAMILY, family)
826	__ADD(LINK_ATTR_ARPTYPE, arptype)
827	__ADD(LINK_ATTR_STATS, stats)
828	__ADD(LINK_ATTR_CHANGE, change)
829	__ADD(LINK_ATTR_OPERSTATE, operstate)
830	__ADD(LINK_ATTR_LINKMODE, linkmode)
831};
832
833static char *link_attrs2str(int attrs, char *buf, size_t len)
834{
835	return __flags2str(attrs, buf, len, link_attrs,
836			   ARRAY_SIZE(link_attrs));
837}
838
839/**
840 * @name Allocation/Freeing
841 * @{
842 */
843
844struct rtnl_link *rtnl_link_alloc(void)
845{
846	return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
847}
848
849void rtnl_link_put(struct rtnl_link *link)
850{
851	nl_object_put((struct nl_object *) link);
852}
853
854/** @} */
855
856/**
857 * @name Cache Management
858 * @{
859 */
860
861
862/**
863 * Allocate link cache and fill in all configured links.
864 * @arg sk		Netlink socket.
865 * @arg result		Pointer to store resulting cache.
866 *
867 * Allocates a new link cache, initializes it properly and updates it
868 * to include all links currently configured in the kernel.
869 *
870 * @return 0 on success or a negative error code.
871 */
872int rtnl_link_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
873{
874	return nl_cache_alloc_and_fill(&rtnl_link_ops, sk, result);
875}
876
877/**
878 * Look up link by interface index in the provided cache
879 * @arg cache		link cache
880 * @arg ifindex		link interface index
881 *
882 * The caller owns a reference on the returned object and
883 * must give the object back via rtnl_link_put().
884 *
885 * @return pointer to link inside the cache or NULL if no match was found.
886 */
887struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
888{
889	struct rtnl_link *link;
890
891	if (cache->c_ops != &rtnl_link_ops)
892		return NULL;
893
894	nl_list_for_each_entry(link, &cache->c_items, ce_list) {
895		if (link->l_index == ifindex) {
896			nl_object_get((struct nl_object *) link);
897			return link;
898		}
899	}
900
901	return NULL;
902}
903
904/**
905 * Look up link by link name in the provided cache
906 * @arg cache		link cache
907 * @arg name		link name
908 *
909 * The caller owns a reference on the returned object and
910 * must give the object back via rtnl_link_put().
911 *
912 * @return pointer to link inside the cache or NULL if no match was found.
913 */
914struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
915					 const char *name)
916{
917	struct rtnl_link *link;
918
919	if (cache->c_ops != &rtnl_link_ops)
920		return NULL;
921
922	nl_list_for_each_entry(link, &cache->c_items, ce_list) {
923		if (!strcmp(name, link->l_name)) {
924			nl_object_get((struct nl_object *) link);
925			return link;
926		}
927	}
928
929	return NULL;
930}
931
932/** @} */
933
934/**
935 * @name Link Modifications
936 * @{
937 */
938
939/**
940 * Builds a netlink change request message to change link attributes
941 * @arg old		link to be changed
942 * @arg tmpl		template with requested changes
943 * @arg flags		additional netlink message flags
944 *
945 * Builds a new netlink message requesting a change of link attributes.
946 * The netlink message header isn't fully equipped with all relevant
947 * fields and must be sent out via nl_send_auto_complete() or
948 * supplemented as needed.
949 * \a old must point to a link currently configured in the kernel
950 * and \a tmpl must contain the attributes to be changed set via
951 * \c rtnl_link_set_* functions.
952 *
953 * @return New netlink message
954 * @note Not all attributes can be changed, see
955 *       \ref link_changeable "Changeable Attributes" for more details.
956 */
957int rtnl_link_build_change_request(struct rtnl_link *old,
958				   struct rtnl_link *tmpl, int flags,
959				   struct nl_msg **result)
960{
961	struct nl_msg *msg;
962	struct ifinfomsg ifi = {
963		.ifi_family = old->l_family,
964		.ifi_index = old->l_index,
965	};
966
967	if (tmpl->ce_mask & LINK_ATTR_FLAGS) {
968		ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask;
969		ifi.ifi_flags |= tmpl->l_flags;
970	}
971
972	msg = nlmsg_alloc_simple(RTM_SETLINK, flags);
973	if (!msg)
974		return -NLE_NOMEM;
975
976	if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
977		goto nla_put_failure;
978
979	if (tmpl->ce_mask & LINK_ATTR_ADDR)
980		NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr);
981
982	if (tmpl->ce_mask & LINK_ATTR_BRD)
983		NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast);
984
985	if (tmpl->ce_mask & LINK_ATTR_MTU)
986		NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu);
987
988	if (tmpl->ce_mask & LINK_ATTR_TXQLEN)
989		NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen);
990
991	if (tmpl->ce_mask & LINK_ATTR_WEIGHT)
992		NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight);
993
994	if (tmpl->ce_mask & LINK_ATTR_IFNAME)
995		NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name);
996
997	if (tmpl->ce_mask & LINK_ATTR_OPERSTATE)
998		NLA_PUT_U8(msg, IFLA_OPERSTATE, tmpl->l_operstate);
999
1000	if (tmpl->ce_mask & LINK_ATTR_LINKMODE)
1001		NLA_PUT_U8(msg, IFLA_LINKMODE, tmpl->l_linkmode);
1002
1003	if ((tmpl->ce_mask & LINK_ATTR_LINKINFO) && tmpl->l_info_ops &&
1004	    tmpl->l_info_ops->io_put_attrs) {
1005		struct nlattr *info;
1006
1007		if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
1008			goto nla_put_failure;
1009
1010		NLA_PUT_STRING(msg, IFLA_INFO_KIND, tmpl->l_info_ops->io_name);
1011
1012		if (tmpl->l_info_ops->io_put_attrs(msg, tmpl) < 0)
1013			goto nla_put_failure;
1014
1015		nla_nest_end(msg, info);
1016	}
1017
1018	*result = msg;
1019	return 0;
1020
1021nla_put_failure:
1022	nlmsg_free(msg);
1023	return -NLE_MSGSIZE;
1024}
1025
1026/**
1027 * Change link attributes
1028 * @arg sk		Netlink socket.
1029 * @arg old		link to be changed
1030 * @arg tmpl		template with requested changes
1031 * @arg flags		additional netlink message flags
1032 *
1033 * Builds a new netlink message by calling rtnl_link_build_change_request(),
1034 * sends the request to the kernel and waits for the next ACK to be
1035 * received, i.e. blocks until the request has been processed.
1036 *
1037 * @return 0 on success or a negative error code
1038 * @note Not all attributes can be changed, see
1039 *       \ref link_changeable "Changeable Attributes" for more details.
1040 */
1041int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *old,
1042		     struct rtnl_link *tmpl, int flags)
1043{
1044	struct nl_msg *msg;
1045	int err;
1046
1047	if ((err = rtnl_link_build_change_request(old, tmpl, flags, &msg)) < 0)
1048		return err;
1049
1050	if ((err = nl_send_auto_complete(sk, msg)) < 0)
1051		return err;
1052
1053	nlmsg_free(msg);
1054	return nl_wait_for_ack(sk);
1055}
1056
1057/** @} */
1058
1059/**
1060 * @name Name <-> Index Translations
1061 * @{
1062 */
1063
1064/**
1065 * Translate an interface index to the corresponding link name
1066 * @arg cache		link cache
1067 * @arg ifindex		link interface index
1068 * @arg dst		destination buffer
1069 * @arg len		length of destination buffer
1070 *
1071 * Translates the specified interface index to the corresponding
1072 * link name and stores the name in the destination buffer.
1073 *
1074 * @return link name or NULL if no match was found.
1075 */
1076char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
1077			size_t len)
1078{
1079	struct rtnl_link *link = rtnl_link_get(cache, ifindex);
1080
1081	if (link) {
1082		strncpy(dst, link->l_name, len - 1);
1083		rtnl_link_put(link);
1084		return dst;
1085	}
1086
1087	return NULL;
1088}
1089
1090/**
1091 * Translate a link name to the corresponding interface index
1092 * @arg cache		link cache
1093 * @arg name		link name
1094 *
1095 * @return interface index or 0 if no match was found.
1096 */
1097int rtnl_link_name2i(struct nl_cache *cache, const char *name)
1098{
1099	int ifindex = 0;
1100	struct rtnl_link *link;
1101
1102	link = rtnl_link_get_by_name(cache, name);
1103	if (link) {
1104		ifindex = link->l_index;
1105		rtnl_link_put(link);
1106	}
1107
1108	return ifindex;
1109}
1110
1111/** @} */
1112
1113/**
1114 * @name Link Flags Translations
1115 * @{
1116 */
1117
1118static struct trans_tbl link_flags[] = {
1119	__ADD(IFF_LOOPBACK, loopback)
1120	__ADD(IFF_BROADCAST, broadcast)
1121	__ADD(IFF_POINTOPOINT, pointopoint)
1122	__ADD(IFF_MULTICAST, multicast)
1123	__ADD(IFF_NOARP, noarp)
1124	__ADD(IFF_ALLMULTI, allmulti)
1125	__ADD(IFF_PROMISC, promisc)
1126	__ADD(IFF_MASTER, master)
1127	__ADD(IFF_SLAVE, slave)
1128	__ADD(IFF_DEBUG, debug)
1129	__ADD(IFF_DYNAMIC, dynamic)
1130	__ADD(IFF_AUTOMEDIA, automedia)
1131	__ADD(IFF_PORTSEL, portsel)
1132	__ADD(IFF_NOTRAILERS, notrailers)
1133	__ADD(IFF_UP, up)
1134	__ADD(IFF_RUNNING, running)
1135	__ADD(IFF_LOWER_UP, lowerup)
1136	__ADD(IFF_DORMANT, dormant)
1137	__ADD(IFF_ECHO, echo)
1138};
1139
1140char * rtnl_link_flags2str(int flags, char *buf, size_t len)
1141{
1142	return __flags2str(flags, buf, len, link_flags,
1143			   ARRAY_SIZE(link_flags));
1144}
1145
1146int rtnl_link_str2flags(const char *name)
1147{
1148	return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
1149}
1150
1151/** @} */
1152
1153/**
1154 * @name Link Statistics Translations
1155 * @{
1156 */
1157
1158static struct trans_tbl link_stats[] = {
1159	__ADD(RTNL_LINK_RX_PACKETS, rx_packets)
1160	__ADD(RTNL_LINK_TX_PACKETS, tx_packets)
1161	__ADD(RTNL_LINK_RX_BYTES, rx_bytes)
1162	__ADD(RTNL_LINK_TX_BYTES, tx_bytes)
1163	__ADD(RTNL_LINK_RX_ERRORS, rx_errors)
1164	__ADD(RTNL_LINK_TX_ERRORS, tx_errors)
1165	__ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
1166	__ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
1167	__ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
1168	__ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
1169	__ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
1170	__ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
1171	__ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
1172	__ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
1173	__ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
1174	__ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
1175	__ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
1176	__ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
1177	__ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
1178	__ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
1179	__ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
1180	__ADD(RTNL_LINK_TX_COLLISIONS, tx_collision)
1181	__ADD(RTNL_LINK_MULTICAST, multicast)
1182};
1183
1184char *rtnl_link_stat2str(int st, char *buf, size_t len)
1185{
1186	return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
1187}
1188
1189int rtnl_link_str2stat(const char *name)
1190{
1191	return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
1192}
1193
1194/** @} */
1195
1196/**
1197 * @name Link Operstate Translations
1198 * @{
1199 */
1200
1201static struct trans_tbl link_operstates[] = {
1202	__ADD(IF_OPER_UNKNOWN, unknown)
1203	__ADD(IF_OPER_NOTPRESENT, notpresent)
1204	__ADD(IF_OPER_DOWN, down)
1205	__ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
1206	__ADD(IF_OPER_TESTING, testing)
1207	__ADD(IF_OPER_DORMANT, dormant)
1208	__ADD(IF_OPER_UP, up)
1209};
1210
1211char *rtnl_link_operstate2str(int st, char *buf, size_t len)
1212{
1213	return __type2str(st, buf, len, link_operstates,
1214			  ARRAY_SIZE(link_operstates));
1215}
1216
1217int rtnl_link_str2operstate(const char *name)
1218{
1219	return __str2type(name, link_operstates,
1220			  ARRAY_SIZE(link_operstates));
1221}
1222
1223/** @} */
1224
1225/**
1226 * @name Link Mode Translations
1227 * @{
1228 */
1229
1230static struct trans_tbl link_modes[] = {
1231	__ADD(IF_LINK_MODE_DEFAULT, default)
1232	__ADD(IF_LINK_MODE_DORMANT, dormant)
1233};
1234
1235char *rtnl_link_mode2str(int st, char *buf, size_t len)
1236{
1237	return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
1238}
1239
1240int rtnl_link_str2mode(const char *name)
1241{
1242	return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
1243}
1244
1245/** @} */
1246
1247/**
1248 * @name Attributes
1249 * @{
1250 */
1251
1252void rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc)
1253{
1254	strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1);
1255	link->ce_mask |= LINK_ATTR_QDISC;
1256}
1257
1258char *rtnl_link_get_qdisc(struct rtnl_link *link)
1259{
1260	if (link->ce_mask & LINK_ATTR_QDISC)
1261		return link->l_qdisc;
1262	else
1263		return NULL;
1264}
1265
1266void rtnl_link_set_name(struct rtnl_link *link, const char *name)
1267{
1268	strncpy(link->l_name, name, sizeof(link->l_name) - 1);
1269	link->ce_mask |= LINK_ATTR_IFNAME;
1270}
1271
1272char *rtnl_link_get_name(struct rtnl_link *link)
1273{
1274	if (link->ce_mask & LINK_ATTR_IFNAME)
1275		return link->l_name;
1276	else
1277		return NULL;
1278}
1279
1280static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
1281				 struct nl_addr *new, int flag)
1282{
1283	if (*pos)
1284		nl_addr_put(*pos);
1285
1286	nl_addr_get(new);
1287	*pos = new;
1288
1289	link->ce_mask |= flag;
1290}
1291
1292void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
1293{
1294	__assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
1295}
1296
1297struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
1298{
1299	if (link->ce_mask & LINK_ATTR_ADDR)
1300		return link->l_addr;
1301	else
1302		return NULL;
1303}
1304
1305void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd)
1306{
1307	__assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD);
1308}
1309
1310struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
1311{
1312	if (link->ce_mask & LINK_ATTR_BRD)
1313		return link->l_bcast;
1314	else
1315		return NULL;
1316}
1317
1318void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
1319{
1320	link->l_flag_mask |= flags;
1321	link->l_flags |= flags;
1322	link->ce_mask |= LINK_ATTR_FLAGS;
1323}
1324
1325void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
1326{
1327	link->l_flag_mask |= flags;
1328	link->l_flags &= ~flags;
1329	link->ce_mask |= LINK_ATTR_FLAGS;
1330}
1331
1332unsigned int rtnl_link_get_flags(struct rtnl_link *link)
1333{
1334	return link->l_flags;
1335}
1336
1337void rtnl_link_set_family(struct rtnl_link *link, int family)
1338{
1339	link->l_family = family;
1340	link->ce_mask |= LINK_ATTR_FAMILY;
1341}
1342
1343int rtnl_link_get_family(struct rtnl_link *link)
1344{
1345	if (link->l_family & LINK_ATTR_FAMILY)
1346		return link->l_family;
1347	else
1348		return AF_UNSPEC;
1349}
1350
1351void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
1352{
1353	link->l_arptype = arptype;
1354}
1355
1356unsigned int rtnl_link_get_arptype(struct rtnl_link *link)
1357{
1358	return link->l_arptype;
1359}
1360
1361void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
1362{
1363	link->l_index = ifindex;
1364	link->ce_mask |= LINK_ATTR_IFINDEX;
1365}
1366
1367int rtnl_link_get_ifindex(struct rtnl_link *link)
1368{
1369	return link->l_index;
1370}
1371
1372void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
1373{
1374	link->l_mtu = mtu;
1375	link->ce_mask |= LINK_ATTR_MTU;
1376}
1377
1378unsigned int rtnl_link_get_mtu(struct rtnl_link *link)
1379{
1380	if (link->ce_mask & LINK_ATTR_MTU)
1381		return link->l_mtu;
1382	else
1383		return 0;
1384}
1385
1386void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
1387{
1388	link->l_txqlen = txqlen;
1389	link->ce_mask |= LINK_ATTR_TXQLEN;
1390}
1391
1392unsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
1393{
1394	if (link->ce_mask & LINK_ATTR_TXQLEN)
1395		return link->l_txqlen;
1396	else
1397		return UINT_MAX;
1398}
1399
1400void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
1401{
1402	link->l_weight = weight;
1403	link->ce_mask |= LINK_ATTR_WEIGHT;
1404}
1405
1406unsigned int rtnl_link_get_weight(struct rtnl_link *link)
1407{
1408	if (link->ce_mask & LINK_ATTR_WEIGHT)
1409		return link->l_weight;
1410	else
1411		return UINT_MAX;
1412}
1413
1414void rtnl_link_set_link(struct rtnl_link *link, int ifindex)
1415{
1416	link->l_link = ifindex;
1417	link->ce_mask |= LINK_ATTR_LINK;
1418}
1419
1420int rtnl_link_get_link(struct rtnl_link *link)
1421{
1422	return link->l_link;
1423}
1424
1425void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
1426{
1427	link->l_master = ifindex;
1428	link->ce_mask |= LINK_ATTR_MASTER;
1429}
1430
1431int rtnl_link_get_master(struct rtnl_link *link)
1432{
1433	return link->l_master;
1434}
1435
1436void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate)
1437{
1438	link->l_operstate = operstate;
1439	link->ce_mask |= LINK_ATTR_OPERSTATE;
1440}
1441
1442uint8_t rtnl_link_get_operstate(struct rtnl_link *link)
1443{
1444	if (link->ce_mask & LINK_ATTR_OPERSTATE)
1445		return link->l_operstate;
1446	else
1447		return IF_OPER_UNKNOWN;
1448}
1449
1450void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t linkmode)
1451{
1452	link->l_linkmode = linkmode;
1453	link->ce_mask |= LINK_ATTR_LINKMODE;
1454}
1455
1456uint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
1457{
1458	if (link->ce_mask & LINK_ATTR_LINKMODE)
1459		return link->l_linkmode;
1460	else
1461		return IF_LINK_MODE_DEFAULT;
1462}
1463
1464uint64_t rtnl_link_get_stat(struct rtnl_link *link, int id)
1465{
1466	if (id < 0 || id > RTNL_LINK_STATS_MAX)
1467		return 0;
1468
1469	return link->l_stats[id];
1470}
1471
1472/**
1473 * Specify the info type of a link
1474 * @arg link	link object
1475 * @arg type	info type
1476 *
1477 * Looks up the info type and prepares the link to store info type
1478 * specific attributes. If an info type has been assigned already
1479 * it will be released with all changes lost.
1480 *
1481 * @return 0 on success or a negative errror code.
1482 */
1483int rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
1484{
1485	struct rtnl_link_info_ops *io;
1486	int err;
1487
1488	if ((io = rtnl_link_info_ops_lookup(type)) == NULL)
1489		return -NLE_OPNOTSUPP;
1490
1491	if (link->l_info_ops)
1492		release_link_info(link);
1493
1494	if ((err = io->io_alloc(link)) < 0)
1495		return err;
1496
1497	link->l_info_ops = io;
1498
1499	return 0;
1500}
1501
1502/**
1503 * Return info type of a link
1504 * @arg link	link object
1505 *
1506 * @note The returned pointer is only valid as long as the link exists
1507 * @return Info type name or NULL if unknown.
1508 */
1509char *rtnl_link_get_info_type(struct rtnl_link *link)
1510{
1511	if (link->l_info_ops)
1512		return link->l_info_ops->io_name;
1513	else
1514		return NULL;
1515}
1516
1517/** @} */
1518
1519static struct nl_object_ops link_obj_ops = {
1520	.oo_name		= "route/link",
1521	.oo_size		= sizeof(struct rtnl_link),
1522	.oo_free_data		= link_free_data,
1523	.oo_clone		= link_clone,
1524	.oo_dump[NL_DUMP_BRIEF]	= link_dump_brief,
1525	.oo_dump[NL_DUMP_FULL]	= link_dump_full,
1526	.oo_dump[NL_DUMP_STATS]	= link_dump_stats,
1527	.oo_dump[NL_DUMP_XML]	= link_dump_xml,
1528	.oo_dump[NL_DUMP_ENV]	= link_dump_env,
1529	.oo_compare		= link_compare,
1530	.oo_attrs2str		= link_attrs2str,
1531	.oo_id_attrs		= LINK_ATTR_IFINDEX,
1532};
1533
1534static struct nl_af_group link_groups[] = {
1535	{ AF_UNSPEC,	RTNLGRP_LINK },
1536	{ END_OF_GROUP_LIST },
1537};
1538
1539static struct nl_cache_ops rtnl_link_ops = {
1540	.co_name		= "route/link",
1541	.co_hdrsize		= sizeof(struct ifinfomsg),
1542	.co_msgtypes		= {
1543					{ RTM_NEWLINK, NL_ACT_NEW, "new" },
1544					{ RTM_DELLINK, NL_ACT_DEL, "del" },
1545					{ RTM_GETLINK, NL_ACT_GET, "get" },
1546					END_OF_MSGTYPES_LIST,
1547				  },
1548	.co_protocol		= NETLINK_ROUTE,
1549	.co_groups		= link_groups,
1550	.co_request_update	= link_request_update,
1551	.co_msg_parser		= link_msg_parser,
1552	.co_obj_ops		= &link_obj_ops,
1553};
1554
1555static void __init link_init(void)
1556{
1557	nl_cache_mngt_register(&rtnl_link_ops);
1558}
1559
1560static void __exit link_exit(void)
1561{
1562	nl_cache_mngt_unregister(&rtnl_link_ops);
1563}
1564
1565/** @} */
1566