This commit was generated by cvs2svn to compensate for changes in r786,
[libnl.git] / lib / route / link.c
1 /*
2  * lib/route/link.c     Links (Interfaces)
3  *
4  *      This library is free software; you can redistribute it and/or
5  *      modify it under the terms of the GNU Lesser General Public
6  *      License as published by the Free Software Foundation version 2.1
7  *      of the License.
8  *
9  * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
10  */
11
12 /**
13  * @ingroup rtnl
14  * @defgroup link Links (Interfaces)
15  * @brief
16  *
17  * @par Link Identification
18  * A link can be identified by either its interface index or by its
19  * name. The kernel favours the interface index but falls back to the
20  * interface name if the interface index is lesser-than 0 for kernels
21  * >= 2.6.11. Therefore you can request changes without mapping a
22  * interface name to the corresponding index first.
23  *
24  * @par Changeable Attributes
25  * @anchor link_changeable
26  *  - Link layer address
27  *  - Link layer broadcast address
28  *  - device mapping (ifmap) (>= 2.6.9)
29  *  - MTU (>= 2.6.9)
30  *  - Transmission queue length (>= 2.6.9)
31  *  - Weight (>= 2.6.9)
32  *  - Link name (only via access through interface index) (>= 2.6.9)
33  *  - Flags (>= 2.6.9)
34  *    - IFF_DEBUG
35  *    - IFF_NOTRAILERS
36  *    - IFF_NOARP
37  *    - IFF_DYNAMIC
38  *    - IFF_MULTICAST
39  *    - IFF_PORTSEL
40  *    - IFF_AUTOMEDIA
41  *    - IFF_UP
42  *    - IFF_PROMISC
43  *    - IFF_ALLMULTI
44  *
45  * @par Link Flags (linux/if.h)
46  * @anchor link_flags
47  * @code
48  *   IFF_UP            Status of link (up|down)
49  *   IFF_BROADCAST     Indicates this link allows broadcasting
50  *   IFF_MULTICAST     Indicates this link allows multicasting
51  *   IFF_ALLMULTI      Indicates this link is doing multicast routing
52  *   IFF_DEBUG         Tell the driver to do debugging (currently unused)
53  *   IFF_LOOPBACK      This is the loopback link
54  *   IFF_POINTOPOINT   Point-to-point link
55  *   IFF_NOARP         Link is unable to perform ARP
56  *   IFF_PROMISC       Status of promiscious mode flag
57  *   IFF_MASTER        Used by teql
58  *   IFF_SLAVE         Used by teql
59  *   IFF_PORTSEL       Indicates this link allows port selection
60  *   IFF_AUTOMEDIA     Indicates this link selects port automatically
61  *   IFF_DYNAMIC       Indicates the address of this link is dynamic
62  *   IFF_RUNNING       Link is running and carrier is ok.
63  *   IFF_NOTRAILERS    Unused, BSD compat.
64  * @endcode
65  *
66  * @par Notes on IFF_PROMISC and IFF_ALLMULTI flags
67  * Although you can query the status of IFF_PROMISC and IFF_ALLMULTI
68  * they do not represent the actual state in the kernel but rather
69  * whether the flag has been enabled/disabled by userspace. The link
70  * may be in promiscious mode even if IFF_PROMISC is not set in a link
71  * dump request response because promiscity might be needed by the driver
72  * for a period of time.
73  *
74  * @par 1) Retrieving information about available links
75  * @code
76  * // The first step is to retrieve a list of all available interfaces within
77  * // the kernel and put them into a cache.
78  * struct nl_cache *cache = rtnl_link_alloc_cache(nl_handle);
79  *
80  * // In a second step, a specific link may be looked up by either interface
81  * // index or interface name.
82  * struct rtnl_link *link = rtnl_link_get_by_name(cache, "lo");
83  *
84  * // rtnl_link_get_by_name() is the short version for translating the
85  * // interface name to an interface index first like this:
86  * int ifindex = rtnl_link_name2i(cache, "lo");
87  * struct rtnl_link *link = rtnl_link_get(cache, ifindex);
88  *
89  * // After successful usage, the object must be given back to the cache
90  * rtnl_link_put(link);
91  * @endcode
92  *
93  * @par 2) Changing link attributes
94  * @code
95  * // In order to change any attributes of an existing link, we must allocate
96  * // a new link to hold the change requests:
97  * struct rtnl_link *request = rtnl_link_alloc();
98  *
99  * // Now we can go on and specify the attributes we want to change:
100  * rtnl_link_set_weight(request, 300);
101  * rtnl_link_set_mtu(request, 1360);
102  *
103  * // We can also shut an interface down administratively
104  * rtnl_link_unset_flags(request, rtnl_link_str2flags("up"));
105  *
106  * // Actually, we should know which link to change, so let's look it up
107  * struct rtnl_link *old = rtnl_link_get(cache, "eth0");
108  *
109  * // Two ways exist to commit this change request, the first one is to
110  * // build the required netlink message and send it out in one single
111  * // step:
112  * rtnl_link_change(nl_handle, old, request);
113  *
114  * // An alternative way is to build the netlink message and send it
115  * // out yourself using nl_send_auto_complete()
116  * struct nl_msg *msg = rtnl_link_build_change_request(old, request);
117  * nl_send_auto_complete(nl_handle, nlmsg_hdr(msg));
118  * nlmsg_free(msg);
119  *
120  * // Don't forget to give back the link object ;->
121  * rtnl_link_put(old);
122  * @endcode
123  * @{
124  */
125
126 #include <netlink-local.h>
127 #include <netlink/netlink.h>
128 #include <netlink/attr.h>
129 #include <netlink/utils.h>
130 #include <netlink/object.h>
131 #include <netlink/route/rtnl.h>
132 #include <netlink/route/link.h>
133
134 /** @cond SKIP */
135 #define LINK_ATTR_MTU     0x0001
136 #define LINK_ATTR_LINK    0x0002
137 #define LINK_ATTR_TXQLEN  0x0004
138 #define LINK_ATTR_WEIGHT  0x0008
139 #define LINK_ATTR_MASTER  0x0010
140 #define LINK_ATTR_QDISC   0x0020
141 #define LINK_ATTR_MAP     0x0040
142 #define LINK_ATTR_ADDR    0x0080
143 #define LINK_ATTR_BRD     0x0100
144 #define LINK_ATTR_FLAGS   0x0200
145 #define LINK_ATTR_IFNAME  0x0400
146 #define LINK_ATTR_IFINDEX 0x0800
147 #define LINK_ATTR_FAMILY  0x1000
148 #define LINK_ATTR_ARPTYPE 0x2000
149 #define LINK_ATTR_STATS   0x4000
150 #define LINK_ATTR_CHANGE  0x8000
151
152 static struct nl_cache_ops rtnl_link_ops;
153 /** @endcond */
154
155 static void link_free_data(struct nl_object *c)
156 {
157         struct rtnl_link *link = nl_object_priv(c);
158
159         if (link) {
160                 nl_addr_put(link->l_addr);
161                 nl_addr_put(link->l_bcast);
162         }
163 }
164
165 static struct nla_policy link_policy[IFLA_MAX+1] = {
166         [IFLA_IFNAME]   = { .type = NLA_STRING,
167                             .maxlen = IFNAMSIZ },
168         [IFLA_MTU]      = { .type = NLA_U32 },
169         [IFLA_TXQLEN]   = { .type = NLA_U32 },
170         [IFLA_LINK]     = { .type = NLA_U32 },
171         [IFLA_WEIGHT]   = { .type = NLA_U32 },
172         [IFLA_MASTER]   = { .type = NLA_U32 },
173         [IFLA_QDISC]    = { .type = NLA_STRING,
174                             .maxlen = IFQDISCSIZ },
175         [IFLA_STATS]    = { .minlen = sizeof(struct rtnl_link_stats) },
176         [IFLA_MAP]      = { .minlen = sizeof(struct rtnl_link_ifmap) },
177 };
178
179 static int link_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *n,
180                            void *arg)
181 {
182         struct rtnl_link *link;
183         struct ifinfomsg *ifi;
184         struct nlattr *tb[IFLA_MAX+1];
185         struct nl_parser_param *pp = arg;
186         int err;
187
188         link = rtnl_link_alloc();
189         if (link == NULL) {
190                 err = nl_errno(ENOMEM);
191                 goto errout;
192         }
193                 
194         link->ce_msgtype = n->nlmsg_type;
195
196         err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy);
197         if (err < 0)
198                 goto errout;
199
200         if (tb[IFLA_IFNAME] == NULL) {
201                 err = nl_error(EINVAL, "Missing link name TLV");
202                 goto errout;
203         }
204
205         nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
206
207         ifi = nlmsg_data(n);
208         link->l_family = ifi->ifi_family;
209         link->l_arptype = ifi->ifi_type;
210         link->l_index = ifi->ifi_index;
211         link->l_flags = ifi->ifi_flags;
212         link->l_change = ifi->ifi_change;
213         link->l_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY | LINK_ATTR_ARPTYPE|
214                         LINK_ATTR_IFINDEX | LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
215
216         if (tb[IFLA_STATS]) {
217                 struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
218                 
219                 link->l_stats[RTNL_LINK_RX_PACKETS]     = st->rx_packets;
220                 link->l_stats[RTNL_LINK_RX_BYTES]       = st->rx_bytes;
221                 link->l_stats[RTNL_LINK_RX_ERRORS]      = st->rx_errors;
222                 link->l_stats[RTNL_LINK_RX_DROPPED]     = st->rx_dropped;
223                 link->l_stats[RTNL_LINK_RX_COMPRESSED]  = st->rx_compressed;
224                 link->l_stats[RTNL_LINK_RX_FIFO_ERR]    = st->rx_fifo_errors;
225                 link->l_stats[RTNL_LINK_TX_PACKETS]     = st->tx_packets;
226                 link->l_stats[RTNL_LINK_TX_BYTES]       = st->tx_bytes;
227                 link->l_stats[RTNL_LINK_TX_ERRORS]      = st->tx_errors;
228                 link->l_stats[RTNL_LINK_TX_DROPPED]     = st->tx_dropped;
229                 link->l_stats[RTNL_LINK_TX_COMPRESSED]  = st->tx_compressed;
230                 link->l_stats[RTNL_LINK_TX_FIFO_ERR]    = st->tx_fifo_errors;
231                 link->l_stats[RTNL_LINK_RX_LEN_ERR]     = st->rx_length_errors;
232                 link->l_stats[RTNL_LINK_RX_OVER_ERR]    = st->rx_over_errors;
233                 link->l_stats[RTNL_LINK_RX_CRC_ERR]     = st->rx_crc_errors;
234                 link->l_stats[RTNL_LINK_RX_FRAME_ERR]   = st->rx_frame_errors;
235                 link->l_stats[RTNL_LINK_RX_MISSED_ERR]  = st->rx_missed_errors;
236                 link->l_stats[RTNL_LINK_TX_ABORT_ERR]   = st->tx_aborted_errors;
237                 link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors;
238                 link->l_stats[RTNL_LINK_TX_HBEAT_ERR]   = st->tx_heartbeat_errors;
239                 link->l_stats[RTNL_LINK_TX_WIN_ERR]     = st->tx_window_errors;
240                 link->l_stats[RTNL_LINK_MULTICAST]      = st->multicast;
241
242                 link->l_mask |= LINK_ATTR_STATS;
243         }
244
245         if (tb[IFLA_TXQLEN]) {
246                 link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]);
247                 link->l_mask |= LINK_ATTR_TXQLEN;
248         }
249
250         if (tb[IFLA_MTU]) {
251                 link->l_mtu = nla_get_u32(tb[IFLA_MTU]);
252                 link->l_mask |= LINK_ATTR_MTU;
253         }
254
255         if (tb[IFLA_ADDRESS]) {
256                 link->l_addr = nla_get_addr(tb[IFLA_ADDRESS], AF_UNSPEC);
257                 if (link->l_addr == NULL)
258                         goto errout;
259                 nl_addr_set_family(link->l_addr,
260                                    nl_addr_guess_family(link->l_addr));
261                 link->l_mask |= LINK_ATTR_ADDR;
262         }
263
264         if (tb[IFLA_BROADCAST]) {
265                 link->l_bcast = nla_get_addr(tb[IFLA_BROADCAST], AF_UNSPEC);
266                 if (link->l_bcast == NULL)
267                         goto errout;
268                 nl_addr_set_family(link->l_bcast,
269                                    nl_addr_guess_family(link->l_bcast));
270                 link->l_mask |= LINK_ATTR_BRD;
271         }
272
273         if (tb[IFLA_LINK]) {
274                 link->l_link = nla_get_u32(tb[IFLA_LINK]);
275                 link->l_mask |= LINK_ATTR_LINK;
276         }
277
278         if (tb[IFLA_WEIGHT]) {
279                 link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]);
280                 link->l_mask |= LINK_ATTR_WEIGHT;
281         }
282
283         if (tb[IFLA_QDISC]) {
284                 nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
285                 link->l_mask |= LINK_ATTR_QDISC;
286         }
287
288         if (tb[IFLA_MAP]) {
289                 struct rtnl_link_ifmap *map =  nla_data(tb[IFLA_MAP]);
290                 link->l_map.lm_mem_start = map->mem_start;
291                 link->l_map.lm_mem_end   = map->mem_end;
292                 link->l_map.lm_base_addr = map->base_addr;
293                 link->l_map.lm_irq       = map->irq;
294                 link->l_map.lm_dma       = map->dma;
295                 link->l_map.lm_port      = map->port;
296                 link->l_mask |= LINK_ATTR_MAP;
297         }
298
299         if (tb[IFLA_MASTER]) {
300                 link->l_master = nla_get_u32(tb[IFLA_MASTER]);
301                 link->l_mask |= LINK_ATTR_MASTER;
302         }
303
304         err = pp->pp_cb((struct nl_object *) link, pp);
305         if (err < 0)
306                 goto errout;
307
308         return P_ACCEPT;
309
310 errout:
311         rtnl_link_put(link);
312         return err;
313 }
314
315 static int link_request_update(struct nl_cache *c, struct nl_handle *h)
316 {
317         return nl_rtgen_request(h, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
318 }
319
320 static int link_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
321 {
322         char buf[128];
323         struct nl_cache *cache = dp_cache(obj);
324         struct rtnl_link *link = (struct rtnl_link *) obj;
325         int line = 1;
326
327         dp_dump(p, "%s ", link->l_name);
328
329         if (link->l_mask & LINK_ATTR_LINK) {
330                 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
331                 dp_dump(p, "@%s", ll ? ll->l_name : "NONE");
332                 if (ll)
333                         rtnl_link_put(ll);
334         }
335
336         dp_dump(p, "%s ", nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
337         dp_dump(p, "%s ", link->l_addr ?  nl_addr2str(link->l_addr, buf,
338                                                      sizeof(buf)) : "none");
339         dp_dump(p, "mtu %u ", link->l_mtu);
340
341         if (link->l_mask & LINK_ATTR_MASTER) {
342                 struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
343                 dp_dump(p, "master %s ", master ? master->l_name : "inv");
344                 if (master)
345                         rtnl_link_put(master);
346         }
347
348         rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
349         if (buf[0])
350                 dp_dump(p, "<%s>", buf);
351
352         dp_dump(p, "\n");
353
354         return line;
355 }
356
357 static int link_dump_full(struct nl_object *obj, struct nl_dump_params *p)
358 {
359         struct rtnl_link *link = (struct rtnl_link *) obj;
360         char buf[64];
361         int line;
362
363         line = link_dump_brief(obj, p);
364         dp_new_line(p, line++);
365
366         dp_dump(p, "    txqlen %u weight %u ", link->l_txqlen, link->l_weight);
367
368         if (link->l_mask & LINK_ATTR_QDISC)
369                 dp_dump(p, "qdisc %s ", link->l_qdisc);
370
371         if (link->l_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
372                 dp_dump(p, "irq %u ", link->l_map.lm_irq);
373
374         if (link->l_mask & LINK_ATTR_IFINDEX)
375                 dp_dump(p, "index %u ", link->l_index);
376
377         if (link->l_mask & LINK_ATTR_BRD)
378                 dp_dump(p, "brd %s", nl_addr2str(link->l_bcast, buf,
379                                                    sizeof(buf)));
380
381         dp_dump(p, "\n");
382
383         return line;
384 }
385
386 static int link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
387 {
388         struct rtnl_link *link = (struct rtnl_link *) obj;
389         char *unit, fmt[64];
390         float res;
391         int line;
392         
393         line = link_dump_full(obj, p);
394
395         dp_dump_line(p, line++, "    Stats:    bytes    packets     errors "
396                                 "   dropped   fifo-err compressed\n");
397
398         res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
399
400         strcpy(fmt, "    RX  %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
401         fmt[9] = *unit == 'B' ? '9' : '7';
402         
403         dp_dump_line(p, line++, fmt,
404                 res, unit,
405                 link->l_stats[RTNL_LINK_RX_PACKETS],
406                 link->l_stats[RTNL_LINK_RX_ERRORS],
407                 link->l_stats[RTNL_LINK_RX_DROPPED],
408                 link->l_stats[RTNL_LINK_RX_FIFO_ERR],
409                 link->l_stats[RTNL_LINK_RX_COMPRESSED]);
410
411         res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
412
413         strcpy(fmt, "    TX  %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
414         fmt[9] = *unit == 'B' ? '9' : '7';
415         
416         dp_dump_line(p, line++, fmt,
417                 res, unit,
418                 link->l_stats[RTNL_LINK_TX_PACKETS],
419                 link->l_stats[RTNL_LINK_TX_ERRORS],
420                 link->l_stats[RTNL_LINK_TX_DROPPED],
421                 link->l_stats[RTNL_LINK_TX_FIFO_ERR],
422                 link->l_stats[RTNL_LINK_TX_COMPRESSED]);
423
424         dp_dump_line(p, line++, "    Errors:  length       over        crc "
425                                 "     frame     missed  multicast\n");
426
427         dp_dump_line(p, line++, "    RX   %10" PRIu64 " %10" PRIu64 " %10"
428                                 PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
429                                 PRIu64 "\n",
430                 link->l_stats[RTNL_LINK_RX_LEN_ERR],
431                 link->l_stats[RTNL_LINK_RX_OVER_ERR],
432                 link->l_stats[RTNL_LINK_RX_CRC_ERR],
433                 link->l_stats[RTNL_LINK_RX_FRAME_ERR],
434                 link->l_stats[RTNL_LINK_RX_MISSED_ERR],
435                 link->l_stats[RTNL_LINK_MULTICAST]);
436
437         dp_dump_line(p, line++, "    Errors: aborted    carrier  heartbeat "
438                                 "    window  collision\n");
439         
440         dp_dump_line(p, line++, "    TX   %10" PRIu64 " %10" PRIu64 " %10"
441                                 PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
442                 link->l_stats[RTNL_LINK_TX_ABORT_ERR],
443                 link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
444                 link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
445                 link->l_stats[RTNL_LINK_TX_WIN_ERR],
446                 link->l_stats[RTNL_LINK_TX_COLLISIONS]);
447
448         return line;
449 }
450
451 static int link_dump_xml(struct nl_object *obj, struct nl_dump_params *p)
452 {
453         struct rtnl_link *link = (struct rtnl_link *) obj;
454         struct nl_cache *cache = dp_cache(obj);
455         char buf[128];
456         int i, line = 0;
457
458         dp_dump_line(p, line++, "<link name=\"%s\" index=\"%u\">\n",
459                      link->l_name, link->l_index);
460         dp_dump_line(p, line++, "  <family>%s</family>\n",
461                      nl_af2str(link->l_family, buf, sizeof(buf)));
462         dp_dump_line(p, line++, "  <arptype>%s</arptype>\n",
463                      nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
464         dp_dump_line(p, line++, "  <address>%s</address>\n",
465                      nl_addr2str(link->l_addr, buf, sizeof(buf)));
466         dp_dump_line(p, line++, "  <mtu>%u</mtu>\n", link->l_mtu);
467         dp_dump_line(p, line++, "  <txqlen>%u</txqlen>\n", link->l_txqlen);
468         dp_dump_line(p, line++, "  <weight>%u</weight>\n", link->l_weight);
469
470         rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
471         if (buf[0])
472                 dp_dump_line(p, line++, "  <flags>%s</flags>\n", buf);
473
474         if (link->l_mask & LINK_ATTR_QDISC)
475                 dp_dump_line(p, line++, "  <qdisc>%s</qdisc>\n", link->l_qdisc);
476
477         if (link->l_mask & LINK_ATTR_LINK) {
478                 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
479                 dp_dump_line(p, line++, "  <link>%s</link>\n",
480                              ll ? ll->l_name : "none");
481                 if (ll)
482                         rtnl_link_put(ll);
483         }
484
485         if (link->l_mask & LINK_ATTR_MASTER) {
486                 struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
487                 dp_dump_line(p, line++, "  <master>%s</master>\n",
488                              master ? master->l_name : "none");
489                 if (master)
490                         rtnl_link_put(master);
491         }
492
493         if (link->l_mask & LINK_ATTR_BRD)
494                 dp_dump_line(p, line++, "  <broadcast>%s</broadcast>\n",
495                              nl_addr2str(link->l_bcast, buf, sizeof(buf)));
496
497         if (link->l_mask & LINK_ATTR_STATS) {
498                 dp_dump_line(p, line++, "  <stats>\n");
499                 for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
500                         rtnl_link_stat2str(i, buf, sizeof(buf));
501                         dp_dump_line(p, line++,
502                                      "    <%s>%" PRIu64 "</%s>\n",
503                                      buf, link->l_stats[i], buf);
504                 }
505                 dp_dump_line(p, line++, "  </stats>\n");
506         }
507
508         dp_dump_line(p, line++, "</link>\n");
509
510 #if 0
511         uint32_t        l_change;       /**< Change mask */
512         struct rtnl_lifmap l_map;       /**< Interface device mapping */
513 #endif
514
515         return line;
516 }
517
518 static int link_dump_env(struct nl_object *obj, struct nl_dump_params *p)
519 {
520         struct rtnl_link *link = (struct rtnl_link *) obj;
521         struct nl_cache *cache = dp_cache(obj);
522         char buf[128];
523         int i, line = 0;
524
525         dp_dump_line(p, line++, "LINK_NAME=%s\n", link->l_name);
526         dp_dump_line(p, line++, "LINK_IFINDEX=%u\n", link->l_index);
527         dp_dump_line(p, line++, "LINK_FAMILY=%s\n",
528                      nl_af2str(link->l_family, buf, sizeof(buf)));
529         dp_dump_line(p, line++, "LINK_TYPE=%s\n",
530                      nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
531         if (link->l_mask & LINK_ATTR_ADDR)
532                 dp_dump_line(p, line++, "LINK_ADDRESS=%s\n",
533                              nl_addr2str(link->l_addr, buf, sizeof(buf)));
534         dp_dump_line(p, line++, "LINK_MTU=%u\n", link->l_mtu);
535         dp_dump_line(p, line++, "LINK_TXQUEUELEN=%u\n", link->l_txqlen);
536         dp_dump_line(p, line++, "LINK_WEIGHT=%u\n", link->l_weight);
537
538         rtnl_link_flags2str(link->l_flags & ~IFF_RUNNING, buf, sizeof(buf));
539         if (buf[0])
540                 dp_dump_line(p, line++, "LINK_FLAGS=%s\n", buf);
541
542         if (link->l_mask & LINK_ATTR_QDISC)
543                 dp_dump_line(p, line++, "LINK_QDISC=%s\n", link->l_qdisc);
544
545         if (link->l_mask & LINK_ATTR_LINK) {
546                 struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
547
548                 dp_dump_line(p, line++, "LINK_LINK_IFINDEX=%d\n", link->l_link);
549                 if (ll) {
550                         dp_dump_line(p, line++, "LINK_LINK_IFNAME=%s\n",
551                                      ll->l_name);
552                         rtnl_link_put(ll);
553                 }
554         }
555
556         if (link->l_mask & LINK_ATTR_MASTER) {
557                 struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
558                 dp_dump_line(p, line++, "LINK_MASTER=%s\n",
559                              master ? master->l_name : "none");
560                 if (master)
561                         rtnl_link_put(master);
562         }
563
564         if (link->l_mask & LINK_ATTR_BRD)
565                 dp_dump_line(p, line++, "LINK_BROADCAST=%s\n",
566                              nl_addr2str(link->l_bcast, buf, sizeof(buf)));
567
568         if (link->l_mask & LINK_ATTR_STATS) {
569                 for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
570                         char *c = buf;
571
572                         sprintf(buf, "LINK_");
573                         rtnl_link_stat2str(i, buf + 5, sizeof(buf) - 5);
574                         while (*c) {
575                                 *c = toupper(*c);
576                                 c++;
577                         }
578                         dp_dump_line(p, line++,
579                                      "%s=%" PRIu64 "\n", buf, link->l_stats[i]);
580                 }
581         }
582
583         return line;
584 }
585
586 #if 0
587 static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
588 {
589         struct rtnl_link *l = (struct rtnl_link *) a;
590         struct nl_cache *c = dp_cache(a);
591         int nevents = 0;
592
593         if (l->l_change == ~0U) {
594                 if (l->ce_msgtype == RTM_NEWLINK)
595                         cb->le_register(l);
596                 else
597                         cb->le_unregister(l);
598
599                 return 1;
600         }
601
602         if (l->l_change & IFF_SLAVE) {
603                 if (l->l_flags & IFF_SLAVE) {
604                         struct rtnl_link *m = rtnl_link_get(c, l->l_master);
605                         cb->le_new_bonding(l, m);
606                         if (m)
607                                 rtnl_link_put(m);
608                 } else
609                         cb->le_cancel_bonding(l);
610         }
611
612 #if 0
613         if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
614                 dp_dump_line(p, line++, "link %s changed state to %s.\n",
615                         l->l_name, l->l_flags & IFF_UP ? "up" : "down");
616
617         if (l->l_change & IFF_PROMISC) {
618                 dp_new_line(p, line++);
619                 dp_dump(p, "link %s %s promiscuous mode.\n",
620                     l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
621         }
622
623         if (line == 0)
624                 dp_dump_line(p, line++, "link %s sent unknown event.\n",
625                              l->l_name);
626 #endif
627
628         return nevents;
629 }
630 #endif
631
632 static int link_filter(struct nl_object *obj, struct nl_object *filter)
633 {
634         struct rtnl_link *o = (struct rtnl_link *) obj;
635         struct rtnl_link *f = (struct rtnl_link *) filter;
636
637 #define REQ(F) (f->l_mask & LINK_ATTR_##F)
638 #define AVAIL(F) (o->l_mask & LINK_ATTR_##F)
639 #define F_CUS(F, EXPR) (REQ(F) && (!AVAIL(F) || (EXPR)))
640 #define F_INT(F, N) (REQ(F) && (!AVAIL(F) || (o->N != f->N)))
641         if (F_INT(MTU,  l_mtu)                                          ||
642             F_INT(LINK, l_link)                                         ||
643             F_INT(TXQLEN,       l_txqlen)                               ||
644             F_INT(WEIGHT,       l_weight)                               ||
645             F_INT(MASTER,       l_master)                               ||
646             F_INT(IFINDEX,      l_index)                                ||
647             F_INT(FAMILY,       l_family)                               ||
648             F_CUS(QDISC,        strcmp(o->l_qdisc, f->l_qdisc))         ||
649             F_CUS(IFNAME,       strcmp(o->l_name, f->l_name))           ||
650             F_CUS(ADDR, nl_addr_cmp(o->l_addr, f->l_addr))              ||
651             F_CUS(BRD,  nl_addr_cmp(o->l_bcast, f->l_bcast))            ||
652             F_CUS(FLAGS,        f->l_flags ^ (o->l_flags & f->l_flag_mask)))
653                 return 0;
654 #undef REQ
655 #undef AVAIL
656 #undef F_CUS
657 #undef F_INT
658
659         return 1;
660 }
661
662 /**
663  * @name Link Object Allocation/Freeage
664  * @{
665  */
666
667 /**
668  * Allocate and initialize new link object.
669  * @note Free the memory after usage using rtnl_link_put() or rtnl_link_free().
670  * @return Newly allocated link object or NULL if an error occured.
671  */
672 struct rtnl_link *rtnl_link_alloc(void)
673 {
674         return (struct rtnl_link *) nl_object_alloc_from_ops(&rtnl_link_ops);
675 }
676
677 /**
678  * Give back reference on link object.
679  * @arg link            Link object to be given back.
680  *
681  * Decrements the reference counter and frees the object if the
682  * last reference has been released.
683  */
684 void rtnl_link_put(struct rtnl_link *link)
685 {
686         nl_object_put((struct nl_object *) link);
687 }
688 /**
689  * Free link object.
690  * @arg link            Link object to be freed.
691  *
692  * @note Always use rtnl_link_put() unless you're absolutely sure
693  *       that no other user may have a reference on this object.
694  */
695 void rtnl_link_free(struct rtnl_link *link)
696 {
697         nl_object_free((struct nl_object *) link);
698 }
699
700 /** @} */
701
702 /**
703  * @name Link Cache Management
704  * @{
705  */
706
707
708 /**
709  * Allocate link cache and fill in all configured links.
710  * @arg handle          Netlink handle.
711  *
712  * Allocates a new link cache, initializes it properly and updates it
713  * to include all links currently configured in the kernel.
714  *
715  * @note Free the memory after usage.
716  * @return Newly allocated cache or NULL if an error occured.
717  */
718 struct nl_cache *rtnl_link_alloc_cache(struct nl_handle *handle)
719 {
720         struct nl_cache * cache;
721         
722         cache = nl_cache_alloc_from_ops(&rtnl_link_ops);
723         if (cache == NULL)
724                 return NULL;
725         
726         if (nl_cache_update(handle, cache) < 0) {
727                 nl_cache_free(cache);
728                 return NULL;
729         }
730
731         return cache;
732 }
733
734 /**
735  * Look up link by interface index in the provided cache
736  * @arg cache           link cache
737  * @arg ifindex         link interface index
738  *
739  * The caller owns a reference on the returned object and
740  * must give the object back via rtnl_link_put().
741  *
742  * @return pointer to link inside the cache or NULL if no match was found.
743  */
744 struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
745 {
746         struct rtnl_link *link;
747
748         if (cache->c_ops != &rtnl_link_ops)
749                 return NULL;
750
751         nl_list_for_each_entry(link, &cache->c_items, ce_list) {
752                 if (link->l_index == ifindex) {
753                         nl_object_get((struct nl_object *) link);
754                         return link;
755                 }
756         }
757
758         return NULL;
759 }
760
761 /**
762  * Look up link by link name in the provided cache
763  * @arg cache           link cache
764  * @arg name            link name
765  *
766  * The caller owns a reference on the returned object and
767  * must give the object back via rtnl_link_put().
768  *
769  * @return pointer to link inside the cache or NULL if no match was found.
770  */
771 struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
772                                          const char *name)
773 {
774         struct rtnl_link *link;
775
776         if (cache->c_ops != &rtnl_link_ops)
777                 return NULL;
778
779         nl_list_for_each_entry(link, &cache->c_items, ce_list) {
780                 if (!strcmp(name, link->l_name)) {
781                         nl_object_get((struct nl_object *) link);
782                         return link;
783                 }
784         }
785
786         return NULL;
787 }
788
789 /** @} */
790
791 /**
792  * @name Link Modifications
793  * @{
794  */
795
796 /**
797  * Builds a netlink change request message to change link attributes
798  * @arg old             link to be changed
799  * @arg tmpl            template with requested changes
800  * @arg flags           additional netlink message flags
801  *
802  * Builds a new netlink message requesting a change of link attributes.
803  * The netlink message header isn't fully equipped with all relevant
804  * fields and must be sent out via nl_send_auto_complete() or
805  * supplemented as needed.
806  * \a old must point to a link currently configured in the kernel
807  * and \a tmpl must contain the attributes to be changed set via
808  * \c rtnl_link_set_* functions.
809  *
810  * @return New netlink message
811  * @note Not all attributes can be changed, see
812  *       \ref link_changeable "Changeable Attributes" for more details.
813  */
814 struct nl_msg * rtnl_link_build_change_request(struct rtnl_link *old,
815                                                struct rtnl_link *tmpl,
816                                                int flags)
817 {
818         struct nl_msg *msg;
819         struct ifinfomsg ifi = {
820                 .ifi_family = old->l_family,
821                 .ifi_index = old->l_index,
822         };
823
824         if (tmpl->l_mask & LINK_ATTR_FLAGS) {
825                 ifi.ifi_flags = old->l_flags & ~tmpl->l_flag_mask;
826                 ifi.ifi_flags |= tmpl->l_flags;
827         }
828
829         msg = nlmsg_build_simple(RTM_SETLINK, flags);
830         if (!msg)
831                 goto nla_put_failure;
832
833         if (nlmsg_append(msg, &ifi, sizeof(ifi), 1) < 0)
834                 goto nla_put_failure;
835
836         if (tmpl->l_mask & LINK_ATTR_ADDR)
837                 NLA_PUT_ADDR(msg, IFLA_ADDRESS, tmpl->l_addr);
838
839         if (tmpl->l_mask & LINK_ATTR_BRD)
840                 NLA_PUT_ADDR(msg, IFLA_BROADCAST, tmpl->l_bcast);
841
842         if (tmpl->l_mask & LINK_ATTR_MTU)
843                 NLA_PUT_U32(msg, IFLA_MTU, tmpl->l_mtu);
844
845         if (tmpl->l_mask & LINK_ATTR_TXQLEN)
846                 NLA_PUT_U32(msg, IFLA_TXQLEN, tmpl->l_txqlen);
847
848         if (tmpl->l_mask & LINK_ATTR_WEIGHT)
849                 NLA_PUT_U32(msg, IFLA_WEIGHT, tmpl->l_weight);
850
851         if (tmpl->l_mask & LINK_ATTR_IFNAME)
852                 NLA_PUT_STRING(msg, IFLA_IFNAME, tmpl->l_name);
853
854         return msg;
855
856 nla_put_failure:
857         nlmsg_free(msg);
858         return NULL;
859 }
860
861 /**
862  * Change link attributes
863  * @arg handle          netlink handle
864  * @arg old             link to be changed
865  * @arg tmpl            template with requested changes
866  * @arg flags           additional netlink message flags
867  *
868  * Builds a new netlink message by calling rtnl_link_build_change_request(),
869  * sends the request to the kernel and waits for the next ACK to be
870  * received, i.e. blocks until the request has been processed.
871  *
872  * @return 0 on success or a negative error code
873  * @note Not all attributes can be changed, see
874  *       \ref link_changeable "Changeable Attributes" for more details.
875  */
876 int rtnl_link_change(struct nl_handle *handle, struct rtnl_link *old,
877                      struct rtnl_link *tmpl, int flags)
878 {
879         int err;
880         struct nl_msg *msg;
881         
882         msg = rtnl_link_build_change_request(old, tmpl, flags);
883         if (!msg)
884                 return nl_errno(ENOMEM);
885         
886         err = nl_send_auto_complete(handle, msg);
887         if (err < 0)
888                 return err;
889
890         nlmsg_free(msg);
891         return nl_wait_for_ack(handle);
892 }
893
894 /** @} */
895
896 /**
897  * @name Name <-> Index Translations
898  * @{
899  */
900
901 /**
902  * Translate an interface index to the corresponding link name
903  * @arg cache           link cache
904  * @arg ifindex         link interface index
905  * @arg dst             destination buffer
906  * @arg len             length of destination buffer
907  *
908  * Translates the specified interface index to the corresponding
909  * link name and stores the name in the destination buffer.
910  *
911  * @return link name or NULL if no match was found.
912  */
913 char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
914                         size_t len)
915 {
916         struct rtnl_link *link = rtnl_link_get(cache, ifindex);
917
918         if (link) {
919                 strncpy(dst, link->l_name, len - 1);
920                 rtnl_link_put(link);
921                 return dst;
922         }
923
924         return NULL;
925 }
926
927 /**
928  * Translate a link name to the corresponding interface index
929  * @arg cache           link cache
930  * @arg name            link name
931  *
932  * @return interface index or RTNL_LINK_NOT_FOUND if no match was found.
933  */
934 int rtnl_link_name2i(struct nl_cache *cache, const char *name)
935 {
936         int ifindex = RTNL_LINK_NOT_FOUND;
937         struct rtnl_link *link;
938         
939         link = rtnl_link_get_by_name(cache, name);
940         if (link) {
941                 ifindex = link->l_index;
942                 rtnl_link_put(link);
943         }
944
945         return ifindex;
946 }
947
948 /** @} */
949
950 /**
951  * @name Link Flags Translations
952  * @{
953  */
954
955 static struct trans_tbl link_flags[] = {
956         __ADD(IFF_LOOPBACK, loopback)
957         __ADD(IFF_BROADCAST, broadcast)
958         __ADD(IFF_POINTOPOINT, pointopoint)
959         __ADD(IFF_MULTICAST, multicast)
960         __ADD(IFF_NOARP, noarp)
961         __ADD(IFF_ALLMULTI, allmulti)
962         __ADD(IFF_PROMISC, promisc)
963         __ADD(IFF_MASTER, master)
964         __ADD(IFF_SLAVE, slave)
965         __ADD(IFF_DEBUG, debug)
966         __ADD(IFF_DYNAMIC, dynamic)
967         __ADD(IFF_AUTOMEDIA, automedia)
968         __ADD(IFF_PORTSEL, portsel)
969         __ADD(IFF_NOTRAILERS, notrailers)
970         __ADD(IFF_UP, up)
971         __ADD(IFF_RUNNING, running)
972         __ADD(IFF_LOWER_UP, lowerup)
973         __ADD(IFF_DORMANT, dormant)
974 };
975
976 /**
977  * Convert link flags to a character string (Reentrant).
978  * @arg flags           link flags
979  * @arg buf             destination buffer
980  * @arg len             buffer length
981  *
982  * Converts link flags to a character string separated by
983  * commands and stores it in the specified destination buffer.
984  *
985  * \return The destination buffer
986  */
987 char * rtnl_link_flags2str(int flags, char *buf, size_t len)
988 {
989         return __flags2str(flags, buf, len, link_flags,
990                            ARRAY_SIZE(link_flags));
991 }
992
993 /**
994  * Convert a character string to a link flag
995  * @arg name            Name of link flag
996  *
997  * Converts the provided character string specifying a link
998  * link the corresponding numeric value.
999  *
1000  * \return Link flag or a negative value if none was found.
1001  */
1002 int rtnl_link_str2flags(const char *name)
1003 {
1004         return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
1005 }
1006
1007 /** @} */
1008
1009 /**
1010  * @name Link Statistics Translations
1011  * @{
1012  */
1013
1014 static struct trans_tbl link_stats[] = {
1015         __ADD(RTNL_LINK_RX_PACKETS, rx_packets)
1016         __ADD(RTNL_LINK_TX_PACKETS, tx_packets)
1017         __ADD(RTNL_LINK_RX_BYTES, rx_bytes)
1018         __ADD(RTNL_LINK_TX_BYTES, tx_bytes)
1019         __ADD(RTNL_LINK_RX_ERRORS, rx_errors)
1020         __ADD(RTNL_LINK_TX_ERRORS, tx_errors)
1021         __ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
1022         __ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
1023         __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
1024         __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
1025         __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
1026         __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
1027         __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
1028         __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
1029         __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
1030         __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
1031         __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
1032         __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
1033         __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
1034         __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
1035         __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
1036         __ADD(RTNL_LINK_TX_COLLISIONS, tx_collision)
1037         __ADD(RTNL_LINK_MULTICAST, multicast)
1038 };
1039
1040 /**
1041  * Convert a link statistic to a character string (Reentrant).
1042  * @arg st              link statistic
1043  * @arg buf             destination buffer
1044  * @arg len             buffer length
1045  *
1046  * Converts a link statistic to a character string and stores it in
1047  * the specified destination buffer.
1048  *
1049  * @return The destination buffer or the statistic encoded in
1050  *         hexidecimal form if no match was found.
1051  */
1052 char *rtnl_link_stat2str(int st, char *buf, size_t len)
1053 {
1054         return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
1055 }
1056
1057 /**
1058  * Convert a character string to a link statistic
1059  * @arg name            name of link statistic
1060  *
1061  * Converts the provided character string specifying a link
1062  * statistic to the corresponding numeric value.
1063  *
1064  * @return Link statistic or a negative value if none was found.
1065  */
1066 int rtnl_link_str2stat(const char *name)
1067 {
1068         return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
1069 }
1070
1071 /** @} */
1072
1073 /**
1074  * @name Attribute Modification
1075  * @{
1076  */
1077
1078 /**
1079  * Set QDisc name
1080  * @arg link            link to change
1081  * @arg qdisc           qdisc name
1082  */
1083 void rtnl_link_set_qdisc(struct rtnl_link *link, const char *qdisc)
1084 {
1085         strncpy(link->l_qdisc, qdisc, sizeof(link->l_qdisc) - 1);
1086         link->l_mask |= LINK_ATTR_QDISC;
1087 }
1088
1089 /**
1090  * Get QDisc name
1091  * @arg link            link handle
1092  * @return Name of the qdisc or NULL if not set.
1093  */
1094 char *rtnl_link_get_qdisc(struct rtnl_link *link)
1095 {
1096         if (link->l_mask & LINK_ATTR_QDISC)
1097                 return link->l_qdisc;
1098         else
1099                 return NULL;
1100 }
1101
1102 /**
1103  * Set new link name
1104  * @arg link            link to change
1105  * @arg name            new link name
1106  */
1107 void rtnl_link_set_name(struct rtnl_link *link, const char *name)
1108 {
1109         strncpy(link->l_name, name, sizeof(link->l_name) - 1);
1110         link->l_mask |= LINK_ATTR_IFNAME;
1111 }
1112
1113 /**
1114  * Get link name
1115  * @arg link            link handle
1116  * @return Name of the link or NULL if not set.
1117  */
1118 char *rtnl_link_get_name(struct rtnl_link *link)
1119 {
1120         if (link->l_mask & LINK_ATTR_IFNAME)
1121                 return link->l_name;
1122         else
1123                 return NULL;
1124 }
1125
1126 static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
1127                                  struct nl_addr *new, int flag)
1128 {
1129         if (*pos)
1130                 nl_addr_put(*pos);
1131
1132         nl_addr_get(new);
1133         *pos = new;
1134
1135         link->l_mask |= flag;
1136 }
1137
1138 /**
1139  * Set link layer address
1140  * @arg link            link to change
1141  * @arg addr            new link layer address
1142  */
1143 void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
1144 {
1145         __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
1146 }
1147
1148 /**
1149  * Get link layer address
1150  * @arg link            link handle
1151  * @return link layer address or NULL if not set
1152  */
1153 struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
1154 {
1155         if (link->l_mask & LINK_ATTR_ADDR)
1156                 return link->l_addr;
1157         else
1158                 return NULL;
1159 }
1160
1161 /**
1162  * Set link layer broadcast address
1163  * @arg link            link to change
1164  * @arg brd             new link layer broadcast address
1165  *
1166  * Assigns the new broadcast address to the specified link handle.
1167  *
1168  * @note The prefix length of the address will be ignored.
1169  */
1170 void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *brd)
1171 {
1172         __assign_addr(link, &link->l_bcast, brd, LINK_ATTR_BRD);
1173 }
1174
1175 /**
1176  * Get link layer broadcast address
1177  * @arg link            link handle
1178  * @return Link layer broadcast address or NULL if not set
1179  */
1180 struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
1181 {
1182         if (link->l_mask & LINK_ATTR_BRD)
1183                 return link->l_bcast;
1184         else
1185                 return NULL;
1186 }
1187
1188 /**
1189  * Set flags
1190  * @arg link            link to change
1191  * @arg flags           flags to set (see \ref link_flags "Link Flags")
1192  */
1193 void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
1194 {
1195         link->l_flag_mask |= flags;
1196         link->l_flags |= flags;
1197         link->l_mask |= LINK_ATTR_FLAGS;
1198 }
1199
1200 /**
1201  * Unset flags
1202  * @arg link            link to change
1203  * @arg flags           flags to unset (see \ref link_flags "Link Flags")
1204  */
1205 void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
1206 {
1207         link->l_flag_mask |= flags;
1208         link->l_flags &= ~flags;
1209         link->l_mask |= LINK_ATTR_FLAGS;
1210 }
1211
1212 /**
1213  * Get flags
1214  * @arg link            link handle
1215  * @return Link flags
1216  */
1217 unsigned int rtnl_link_get_flags(struct rtnl_link *link)
1218 {
1219         return link->l_flags;
1220 }
1221
1222 /**
1223  * Set link layer address family
1224  * @arg link            link to change
1225  * @arg family          new address family
1226  */
1227 void rtnl_link_set_family(struct rtnl_link *link, int family)
1228 {
1229         link->l_family = family;
1230         link->l_mask |= LINK_ATTR_FAMILY;
1231 }
1232
1233 /**
1234  * Get link layer address family
1235  * @arg link            link handle
1236  * @return Link layer address family or AF_UNSPEC if not set.
1237  */
1238 int rtnl_link_get_family(struct rtnl_link *link)
1239 {
1240         if (link->l_family & LINK_ATTR_FAMILY)
1241                 return link->l_family;
1242         else
1243                 return AF_UNSPEC;
1244 }
1245
1246 /**
1247  * Set link layer type
1248  * @arg link            link handle
1249  * @arg arptype         Link layer type.
1250  */
1251 void rtnl_link_set_type(struct rtnl_link *link, unsigned int arptype)
1252 {
1253         link->l_arptype = arptype;
1254 }
1255
1256 /**
1257  * Get link layer type
1258  * @arg link            link handle
1259  * @return Link layer type.
1260  */
1261 unsigned int rtnl_link_get_arptype(struct rtnl_link *link)
1262 {
1263         return link->l_arptype;
1264 }
1265
1266 /**
1267  * Set interface index
1268  * @arg link            link to change
1269  * @arg ifindex         new interface index
1270  */
1271 void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
1272 {
1273         link->l_index = ifindex;
1274         link->l_mask |= LINK_ATTR_IFINDEX;
1275 }
1276
1277 /**
1278  * Get interface index
1279  * @arg link            link handle
1280  * @return interface index or RTNL_LINK_NOT_FOUND if not set.
1281  */
1282 int rtnl_link_get_ifindex(struct rtnl_link *link)
1283 {
1284         if (link->l_mask & LINK_ATTR_IFINDEX)
1285                 return link->l_index;
1286         else
1287                 return RTNL_LINK_NOT_FOUND;
1288 }
1289
1290 /**
1291  * Set Maximum Transmission Unit
1292  * @arg link            link to change
1293  * @arg mtu             new MTU
1294  */
1295 void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
1296 {
1297         link->l_mtu = mtu;
1298         link->l_mask |= LINK_ATTR_MTU;
1299 }
1300
1301 /**
1302  * Get Maximum Transmission Unit
1303  * @arg link            link handle
1304  * @return Link MTU or 0 if MTU is not set.
1305  */
1306 unsigned int rtnl_link_get_mtu(struct rtnl_link *link)
1307 {
1308         if (link->l_mask & LINK_ATTR_MTU)
1309                 return link->l_mtu;
1310         else
1311                 return 0;
1312 }
1313
1314 /**
1315  * Set Transmission Queue Length
1316  * @arg link            link to change
1317  * @arg txqlen          new TX queue length
1318  * @note The unit of the transmission queue length depends on the
1319  *       link type, a common unit is \a packets.
1320  */
1321 void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
1322 {
1323         link->l_txqlen = txqlen;
1324         link->l_mask |= LINK_ATTR_TXQLEN;
1325 }
1326
1327 /**
1328  * Get Transmission Queue Length
1329  * @arg link            link handle
1330  * @return Transmission Queue Length or UINT_MAX if not set.
1331  */
1332 unsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
1333 {
1334         if (link->l_mask & LINK_ATTR_TXQLEN)
1335                 return link->l_txqlen;
1336         else
1337                 return UINT_MAX;
1338 }
1339
1340 /**
1341  * Set Weight
1342  * @arg link            link to change
1343  * @arg weight          new weight
1344  */
1345 void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
1346 {
1347         link->l_weight = weight;
1348         link->l_mask |= LINK_ATTR_WEIGHT;
1349 }
1350
1351 /**
1352  * Get Weight
1353  * @arg link            link handle
1354  * @return Link weight or UINT_MAX if not set.
1355  */
1356 unsigned int rtnl_link_get_weight(struct rtnl_link *link)
1357 {
1358         if (link->l_mask & LINK_ATTR_WEIGHT)
1359                 return link->l_weight;
1360         else
1361                 return UINT_MAX;
1362 }
1363
1364 /**
1365  * Set parent interface index
1366  * @arg link            link to change
1367  * @arg ifindex         new parent's interface index
1368  */
1369 void rtnl_link_set_link(struct rtnl_link *link, int ifindex)
1370 {
1371         link->l_link = ifindex;
1372         link->l_mask |= LINK_ATTR_LINK;
1373 }
1374
1375 /**
1376  * Get parent interface index
1377  * @arg link            link handle
1378  * @return Parent interface index or RTNL_LINK_NOT_FOUND if not set
1379  */
1380 int rtnl_link_get_link(struct rtnl_link *link)
1381 {
1382         if (link->l_mask & LINK_ATTR_LINK)
1383                 return link->l_link;
1384         else
1385                 return RTNL_LINK_NOT_FOUND;
1386 }
1387
1388 /**
1389  * Set master interface index
1390  * @arg link            link to change
1391  * @arg ifindex         new master's interface index
1392  */
1393 void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
1394 {
1395         link->l_master = ifindex;
1396         link->l_mask |= LINK_ATTR_MASTER;
1397 }
1398
1399 /**
1400  * Get master interface index
1401  * @arg link            link handle
1402  * @return Interface index of master or RTNL_LINK_NOT_FOUND if not set
1403  */
1404 int rtnl_link_get_master(struct rtnl_link *link)
1405 {
1406         if (link->l_mask & LINK_ATTR_MASTER)
1407                 return link->l_master;
1408         else
1409                 return RTNL_LINK_NOT_FOUND;
1410 }
1411
1412 /**
1413  * Get the statistic specified by the id
1414  * @arg link            link handle
1415  * @arg id              statistic id
1416  * @return The current counter of the specified statistic
1417  */
1418 uint64_t rtnl_link_get_stat(struct rtnl_link *link, int id)
1419 {
1420         if (id < 0 || id > RTNL_LINK_STATS_MAX)
1421                 return 0;
1422
1423         return link->l_stats[id];
1424 }
1425
1426 /** @} */
1427
1428 static struct nl_cache_ops rtnl_link_ops = {
1429         .co_name                = "route/link",
1430         .co_size                = sizeof(struct rtnl_link),
1431         .co_hdrsize             = sizeof(struct ifinfomsg),
1432         .co_msgtypes            = {
1433                                         { RTM_NEWLINK, "new" },
1434                                         { RTM_DELLINK, "delete" },
1435                                         { RTM_GETLINK, "get" },
1436                                         { -1, NULL },
1437                                   },
1438         .co_protocol            = NETLINK_ROUTE,
1439         .co_request_update      = link_request_update,
1440         .co_msg_parser          = link_msg_parser,
1441         .co_free_data           = link_free_data,
1442         .co_dump[NL_DUMP_BRIEF] = link_dump_brief,
1443         .co_dump[NL_DUMP_FULL]  = link_dump_full,
1444         .co_dump[NL_DUMP_STATS] = link_dump_stats,
1445         .co_dump[NL_DUMP_XML]   = link_dump_xml,
1446         .co_dump[NL_DUMP_ENV]   = link_dump_env,
1447         .co_filter              = link_filter,
1448 };
1449
1450 static void __init link_init(void)
1451 {
1452         nl_cache_mngt_register(&rtnl_link_ops);
1453 }
1454
1455 static void __exit link_exit(void)
1456 {
1457         nl_cache_mngt_unregister(&rtnl_link_ops);
1458 }
1459
1460 /** @} */