144d362409d5469aed47d19e7908d19bd194493aThomas Graf/* 244d362409d5469aed47d19e7908d19bd194493aThomas Graf * lib/route/route_obj.c Route Object 344d362409d5469aed47d19e7908d19bd194493aThomas Graf * 444d362409d5469aed47d19e7908d19bd194493aThomas Graf * This library is free software; you can redistribute it and/or 544d362409d5469aed47d19e7908d19bd194493aThomas Graf * modify it under the terms of the GNU Lesser General Public 644d362409d5469aed47d19e7908d19bd194493aThomas Graf * License as published by the Free Software Foundation version 2.1 744d362409d5469aed47d19e7908d19bd194493aThomas Graf * of the License. 844d362409d5469aed47d19e7908d19bd194493aThomas Graf * 9535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> 1044d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 1144d362409d5469aed47d19e7908d19bd194493aThomas Graf 1244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 1344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @ingroup route 1444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @defgroup route_obj Route Object 1544d362409d5469aed47d19e7908d19bd194493aThomas Graf * 1644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par Attributes 1744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code 1844d362409d5469aed47d19e7908d19bd194493aThomas Graf * Name Default 1944d362409d5469aed47d19e7908d19bd194493aThomas Graf * ------------------------------------------------------------- 2044d362409d5469aed47d19e7908d19bd194493aThomas Graf * routing table RT_TABLE_MAIN 2144d362409d5469aed47d19e7908d19bd194493aThomas Graf * scope RT_SCOPE_NOWHERE 2244d362409d5469aed47d19e7908d19bd194493aThomas Graf * tos 0 2344d362409d5469aed47d19e7908d19bd194493aThomas Graf * protocol RTPROT_STATIC 2444d362409d5469aed47d19e7908d19bd194493aThomas Graf * prio 0 2544d362409d5469aed47d19e7908d19bd194493aThomas Graf * family AF_UNSPEC 2644d362409d5469aed47d19e7908d19bd194493aThomas Graf * type RTN_UNICAST 2744d362409d5469aed47d19e7908d19bd194493aThomas Graf * iif NULL 2844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode 2944d362409d5469aed47d19e7908d19bd194493aThomas Graf * 3044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{ 3144d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 3244d362409d5469aed47d19e7908d19bd194493aThomas Graf 3344d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-local.h> 3444d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/netlink.h> 3544d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/cache.h> 3644d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/utils.h> 3744d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/data.h> 3844d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/rtnl.h> 3944d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/route.h> 4044d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/link.h> 41535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf#include <netlink/route/nexthop.h> 4244d362409d5469aed47d19e7908d19bd194493aThomas Graf 4344d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @cond SKIP */ 4444d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_FAMILY 0x000001 4544d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_TOS 0x000002 4644d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_TABLE 0x000004 4744d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_PROTOCOL 0x000008 4844d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_SCOPE 0x000010 4944d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_TYPE 0x000020 5044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_FLAGS 0x000040 5144d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_DST 0x000080 5244d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_SRC 0x000100 5344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_IIF 0x000200 5444d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_OIF 0x000400 5544d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_GATEWAY 0x000800 5644d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_PRIO 0x001000 5744d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_PREF_SRC 0x002000 5844d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_METRICS 0x004000 5944d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_MULTIPATH 0x008000 6044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_REALMS 0x010000 6144d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_CACHEINFO 0x020000 6244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @endcond */ 6344d362409d5469aed47d19e7908d19bd194493aThomas Graf 6444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void route_constructor(struct nl_object *c) 6544d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 6644d362409d5469aed47d19e7908d19bd194493aThomas Graf struct rtnl_route *r = (struct rtnl_route *) c; 6744d362409d5469aed47d19e7908d19bd194493aThomas Graf 68535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf r->rt_family = AF_UNSPEC; 69535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf r->rt_scope = RT_SCOPE_NOWHERE; 70535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf r->rt_table = RT_TABLE_MAIN; 71535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf r->rt_protocol = RTPROT_STATIC; 72535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf r->rt_type = RTN_UNICAST; 73535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 7444d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_init_list_head(&r->rt_nexthops); 7544d362409d5469aed47d19e7908d19bd194493aThomas Graf} 7644d362409d5469aed47d19e7908d19bd194493aThomas Graf 7744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void route_free_data(struct nl_object *c) 7844d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 7944d362409d5469aed47d19e7908d19bd194493aThomas Graf struct rtnl_route *r = (struct rtnl_route *) c; 8044d362409d5469aed47d19e7908d19bd194493aThomas Graf struct rtnl_nexthop *nh, *tmp; 8144d362409d5469aed47d19e7908d19bd194493aThomas Graf 8244d362409d5469aed47d19e7908d19bd194493aThomas Graf if (r == NULL) 8344d362409d5469aed47d19e7908d19bd194493aThomas Graf return; 8444d362409d5469aed47d19e7908d19bd194493aThomas Graf 8544d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_addr_put(r->rt_dst); 8644d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_addr_put(r->rt_src); 8744d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_addr_put(r->rt_pref_src); 8844d362409d5469aed47d19e7908d19bd194493aThomas Graf 8944d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_list_for_each_entry_safe(nh, tmp, &r->rt_nexthops, rtnh_list) { 90535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnl_route_remove_nexthop(r, nh); 9144d362409d5469aed47d19e7908d19bd194493aThomas Graf rtnl_route_nh_free(nh); 9244d362409d5469aed47d19e7908d19bd194493aThomas Graf } 9344d362409d5469aed47d19e7908d19bd194493aThomas Graf} 9444d362409d5469aed47d19e7908d19bd194493aThomas Graf 9544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int route_clone(struct nl_object *_dst, struct nl_object *_src) 9644d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 9744d362409d5469aed47d19e7908d19bd194493aThomas Graf struct rtnl_route *dst = (struct rtnl_route *) _dst; 9844d362409d5469aed47d19e7908d19bd194493aThomas Graf struct rtnl_route *src = (struct rtnl_route *) _src; 9944d362409d5469aed47d19e7908d19bd194493aThomas Graf struct rtnl_nexthop *nh, *new; 10044d362409d5469aed47d19e7908d19bd194493aThomas Graf 10144d362409d5469aed47d19e7908d19bd194493aThomas Graf if (src->rt_dst) 10244d362409d5469aed47d19e7908d19bd194493aThomas Graf if (!(dst->rt_dst = nl_addr_clone(src->rt_dst))) 1038a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_NOMEM; 10444d362409d5469aed47d19e7908d19bd194493aThomas Graf 10544d362409d5469aed47d19e7908d19bd194493aThomas Graf if (src->rt_src) 10644d362409d5469aed47d19e7908d19bd194493aThomas Graf if (!(dst->rt_src = nl_addr_clone(src->rt_src))) 1078a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_NOMEM; 10844d362409d5469aed47d19e7908d19bd194493aThomas Graf 10944d362409d5469aed47d19e7908d19bd194493aThomas Graf if (src->rt_pref_src) 11044d362409d5469aed47d19e7908d19bd194493aThomas Graf if (!(dst->rt_pref_src = nl_addr_clone(src->rt_pref_src))) 1118a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_NOMEM; 11244d362409d5469aed47d19e7908d19bd194493aThomas Graf 11344d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_init_list_head(&dst->rt_nexthops); 11444d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_list_for_each_entry(nh, &src->rt_nexthops, rtnh_list) { 11544d362409d5469aed47d19e7908d19bd194493aThomas Graf new = rtnl_route_nh_clone(nh); 11644d362409d5469aed47d19e7908d19bd194493aThomas Graf if (!new) 1178a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_NOMEM; 11844d362409d5469aed47d19e7908d19bd194493aThomas Graf 11944d362409d5469aed47d19e7908d19bd194493aThomas Graf rtnl_route_add_nexthop(dst, new); 12044d362409d5469aed47d19e7908d19bd194493aThomas Graf } 12144d362409d5469aed47d19e7908d19bd194493aThomas Graf 12244d362409d5469aed47d19e7908d19bd194493aThomas Graf return 0; 12344d362409d5469aed47d19e7908d19bd194493aThomas Graf} 12444d362409d5469aed47d19e7908d19bd194493aThomas Graf 125d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void route_dump_line(struct nl_object *a, struct nl_dump_params *p) 12644d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 12744d362409d5469aed47d19e7908d19bd194493aThomas Graf struct rtnl_route *r = (struct rtnl_route *) a; 12844d362409d5469aed47d19e7908d19bd194493aThomas Graf struct nl_cache *link_cache; 1297072675b40b611279466756ef800cc5dbee92c54Thomas Graf int cache = 0, flags; 13044d362409d5469aed47d19e7908d19bd194493aThomas Graf char buf[64]; 13144d362409d5469aed47d19e7908d19bd194493aThomas Graf 13244d362409d5469aed47d19e7908d19bd194493aThomas Graf link_cache = nl_cache_mngt_require("route/link"); 13344d362409d5469aed47d19e7908d19bd194493aThomas Graf 1347072675b40b611279466756ef800cc5dbee92c54Thomas Graf if (r->rt_flags & RTM_F_CLONED) 1357072675b40b611279466756ef800cc5dbee92c54Thomas Graf cache = 1; 1367072675b40b611279466756ef800cc5dbee92c54Thomas Graf 137d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf nl_dump_line(p, "%s ", nl_af2str(r->rt_family, buf, sizeof(buf))); 138535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1397072675b40b611279466756ef800cc5dbee92c54Thomas Graf if (cache) 1407072675b40b611279466756ef800cc5dbee92c54Thomas Graf nl_dump(p, "cache "); 1417072675b40b611279466756ef800cc5dbee92c54Thomas Graf 142464988628802b76d5b3e50af99158413ac28bd18Thomas Graf if (!(r->ce_mask & ROUTE_ATTR_DST) || 143464988628802b76d5b3e50af99158413ac28bd18Thomas Graf nl_addr_get_len(r->rt_dst) == 0) 144535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, "default "); 145464988628802b76d5b3e50af99158413ac28bd18Thomas Graf else 146535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf))); 14744d362409d5469aed47d19e7908d19bd194493aThomas Graf 1487072675b40b611279466756ef800cc5dbee92c54Thomas Graf if (r->ce_mask & ROUTE_ATTR_TABLE && !cache) 149535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, "table %s ", 150535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnl_route_table2str(r->rt_table, buf, sizeof(buf))); 15144d362409d5469aed47d19e7908d19bd194493aThomas Graf 152535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (r->ce_mask & ROUTE_ATTR_TYPE) 153535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, "type %s ", 154535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_rtntype2str(r->rt_type, buf, sizeof(buf))); 155535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 156535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (r->ce_mask & ROUTE_ATTR_TOS && r->rt_tos != 0) 157535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, "tos %#x ", r->rt_tos); 158535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 159535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (r->ce_mask & ROUTE_ATTR_MULTIPATH) { 160535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct rtnl_nexthop *nh; 161535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 162535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) { 163535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf p->dp_ivar = NH_DUMP_FROM_ONELINE; 164535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnl_route_nh_dump(nh, p); 165535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 166535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 16744d362409d5469aed47d19e7908d19bd194493aThomas Graf 1687072675b40b611279466756ef800cc5dbee92c54Thomas Graf flags = r->rt_flags & ~(RTM_F_CLONED); 1697072675b40b611279466756ef800cc5dbee92c54Thomas Graf if (r->ce_mask & ROUTE_ATTR_FLAGS && flags) { 17044d362409d5469aed47d19e7908d19bd194493aThomas Graf 171535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, "<"); 1727072675b40b611279466756ef800cc5dbee92c54Thomas Graf 17344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define PRINT_FLAG(f) if (flags & RTNH_F_##f) { \ 174535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf flags &= ~RTNH_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); } 17544d362409d5469aed47d19e7908d19bd194493aThomas Graf PRINT_FLAG(DEAD); 17644d362409d5469aed47d19e7908d19bd194493aThomas Graf PRINT_FLAG(ONLINK); 17744d362409d5469aed47d19e7908d19bd194493aThomas Graf PRINT_FLAG(PERVASIVE); 17844d362409d5469aed47d19e7908d19bd194493aThomas Graf#undef PRINT_FLAG 17944d362409d5469aed47d19e7908d19bd194493aThomas Graf 18044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define PRINT_FLAG(f) if (flags & RTM_F_##f) { \ 181535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf flags &= ~RTM_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); } 18244d362409d5469aed47d19e7908d19bd194493aThomas Graf PRINT_FLAG(NOTIFY); 18344d362409d5469aed47d19e7908d19bd194493aThomas Graf PRINT_FLAG(EQUALIZE); 18444d362409d5469aed47d19e7908d19bd194493aThomas Graf PRINT_FLAG(PREFIX); 18544d362409d5469aed47d19e7908d19bd194493aThomas Graf#undef PRINT_FLAG 18644d362409d5469aed47d19e7908d19bd194493aThomas Graf 1877072675b40b611279466756ef800cc5dbee92c54Thomas Graf#define PRINT_FLAG(f) if (flags & RTCF_##f) { \ 1887072675b40b611279466756ef800cc5dbee92c54Thomas Graf flags &= ~RTCF_##f; nl_dump(p, #f "%s", flags ? "," : ""); } 1897072675b40b611279466756ef800cc5dbee92c54Thomas Graf PRINT_FLAG(NOTIFY); 1907072675b40b611279466756ef800cc5dbee92c54Thomas Graf PRINT_FLAG(REDIRECTED); 1917072675b40b611279466756ef800cc5dbee92c54Thomas Graf PRINT_FLAG(DOREDIRECT); 1927072675b40b611279466756ef800cc5dbee92c54Thomas Graf PRINT_FLAG(DIRECTSRC); 1937072675b40b611279466756ef800cc5dbee92c54Thomas Graf PRINT_FLAG(DNAT); 1947072675b40b611279466756ef800cc5dbee92c54Thomas Graf PRINT_FLAG(BROADCAST); 1957072675b40b611279466756ef800cc5dbee92c54Thomas Graf PRINT_FLAG(MULTICAST); 1967072675b40b611279466756ef800cc5dbee92c54Thomas Graf PRINT_FLAG(LOCAL); 1977072675b40b611279466756ef800cc5dbee92c54Thomas Graf#undef PRINT_FLAG 1987072675b40b611279466756ef800cc5dbee92c54Thomas Graf 199535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, ">"); 20044d362409d5469aed47d19e7908d19bd194493aThomas Graf } 20144d362409d5469aed47d19e7908d19bd194493aThomas Graf 202535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, "\n"); 20344d362409d5469aed47d19e7908d19bd194493aThomas Graf} 20444d362409d5469aed47d19e7908d19bd194493aThomas Graf 205d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void route_dump_details(struct nl_object *a, struct nl_dump_params *p) 20644d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 20744d362409d5469aed47d19e7908d19bd194493aThomas Graf struct rtnl_route *r = (struct rtnl_route *) a; 20844d362409d5469aed47d19e7908d19bd194493aThomas Graf struct nl_cache *link_cache; 20944d362409d5469aed47d19e7908d19bd194493aThomas Graf char buf[128]; 210535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf int i; 21144d362409d5469aed47d19e7908d19bd194493aThomas Graf 21244d362409d5469aed47d19e7908d19bd194493aThomas Graf link_cache = nl_cache_mngt_require("route/link"); 21344d362409d5469aed47d19e7908d19bd194493aThomas Graf 214d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf route_dump_line(a, p); 215535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump_line(p, " "); 21644d362409d5469aed47d19e7908d19bd194493aThomas Graf 21744d362409d5469aed47d19e7908d19bd194493aThomas Graf if (r->ce_mask & ROUTE_ATTR_PREF_SRC) 218535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, "preferred-src %s ", 21944d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_addr2str(r->rt_pref_src, buf, sizeof(buf))); 22044d362409d5469aed47d19e7908d19bd194493aThomas Graf 221535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (r->ce_mask & ROUTE_ATTR_SCOPE && r->rt_scope != RT_SCOPE_NOWHERE) 222535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, "scope %s ", 223535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnl_scope2str(r->rt_scope, buf, sizeof(buf))); 22444d362409d5469aed47d19e7908d19bd194493aThomas Graf 22544d362409d5469aed47d19e7908d19bd194493aThomas Graf if (r->ce_mask & ROUTE_ATTR_PRIO) 226535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, "priority %#x ", r->rt_prio); 22744d362409d5469aed47d19e7908d19bd194493aThomas Graf 22844d362409d5469aed47d19e7908d19bd194493aThomas Graf if (r->ce_mask & ROUTE_ATTR_PROTOCOL) 229535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, "protocol %s ", 23044d362409d5469aed47d19e7908d19bd194493aThomas Graf rtnl_route_proto2str(r->rt_protocol, buf, sizeof(buf))); 23144d362409d5469aed47d19e7908d19bd194493aThomas Graf 232d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf if (r->ce_mask & ROUTE_ATTR_IIF) { 233d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf if (link_cache) { 234d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf nl_dump(p, "iif %s ", 235d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf rtnl_link_i2name(link_cache, r->rt_iif, 236d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf buf, sizeof(buf))); 237d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf } else 238d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf nl_dump(p, "iif %d ", r->rt_iif); 239d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf } 24044d362409d5469aed47d19e7908d19bd194493aThomas Graf 241535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (r->ce_mask & ROUTE_ATTR_SRC) 242535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, "src %s ", nl_addr2str(r->rt_src, buf, sizeof(buf))); 24344d362409d5469aed47d19e7908d19bd194493aThomas Graf 244535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, "\n"); 24544d362409d5469aed47d19e7908d19bd194493aThomas Graf 246535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (r->ce_mask & ROUTE_ATTR_MULTIPATH) { 247535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct rtnl_nexthop *nh; 24844d362409d5469aed47d19e7908d19bd194493aThomas Graf 249535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) { 250535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump_line(p, " "); 251535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf p->dp_ivar = NH_DUMP_FROM_DETAILS; 252535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnl_route_nh_dump(nh, p); 253535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, "\n"); 254535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 255535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 25644d362409d5469aed47d19e7908d19bd194493aThomas Graf 257535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) && r->rt_cacheinfo.rtci_error) { 258535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump_line(p, " cacheinfo error %d (%s)\n", 259535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf r->rt_cacheinfo.rtci_error, 260535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf strerror(-r->rt_cacheinfo.rtci_error)); 26144d362409d5469aed47d19e7908d19bd194493aThomas Graf } 26244d362409d5469aed47d19e7908d19bd194493aThomas Graf 26344d362409d5469aed47d19e7908d19bd194493aThomas Graf if (r->ce_mask & ROUTE_ATTR_METRICS) { 264535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump_line(p, " metrics ["); 26544d362409d5469aed47d19e7908d19bd194493aThomas Graf for (i = 0; i < RTAX_MAX; i++) 26644d362409d5469aed47d19e7908d19bd194493aThomas Graf if (r->rt_metrics_mask & (1 << i)) 267535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, "%s %u ", 26844d362409d5469aed47d19e7908d19bd194493aThomas Graf rtnl_route_metric2str(i+1, 26944d362409d5469aed47d19e7908d19bd194493aThomas Graf buf, sizeof(buf)), 27044d362409d5469aed47d19e7908d19bd194493aThomas Graf r->rt_metrics[i]); 271535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump(p, "]\n"); 27244d362409d5469aed47d19e7908d19bd194493aThomas Graf } 27344d362409d5469aed47d19e7908d19bd194493aThomas Graf} 27444d362409d5469aed47d19e7908d19bd194493aThomas Graf 275d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void route_dump_stats(struct nl_object *obj, struct nl_dump_params *p) 27644d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 27744d362409d5469aed47d19e7908d19bd194493aThomas Graf struct rtnl_route *route = (struct rtnl_route *) obj; 27844d362409d5469aed47d19e7908d19bd194493aThomas Graf 279535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route_dump_details(obj, p); 28044d362409d5469aed47d19e7908d19bd194493aThomas Graf 28144d362409d5469aed47d19e7908d19bd194493aThomas Graf if (route->ce_mask & ROUTE_ATTR_CACHEINFO) { 28244d362409d5469aed47d19e7908d19bd194493aThomas Graf struct rtnl_rtcacheinfo *ci = &route->rt_cacheinfo; 283535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 284535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump_line(p, " used %u refcnt %u last-use %us " 285535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf "expires %us\n", 286535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf ci->rtci_used, ci->rtci_clntref, 28744d362409d5469aed47d19e7908d19bd194493aThomas Graf ci->rtci_last_use / nl_get_hz(), 28844d362409d5469aed47d19e7908d19bd194493aThomas Graf ci->rtci_expires / nl_get_hz()); 28944d362409d5469aed47d19e7908d19bd194493aThomas Graf } 29044d362409d5469aed47d19e7908d19bd194493aThomas Graf} 29144d362409d5469aed47d19e7908d19bd194493aThomas Graf 292d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void route_dump_env(struct nl_object *obj, struct nl_dump_params *p) 29344d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 29444d362409d5469aed47d19e7908d19bd194493aThomas Graf struct rtnl_route *route = (struct rtnl_route *) obj; 295d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf struct nl_cache *link_cache; 29644d362409d5469aed47d19e7908d19bd194493aThomas Graf char buf[128]; 297535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 298d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf link_cache = nl_cache_mngt_require("route/link"); 299d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf 300d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf nl_dump_line(p, "ROUTE_FAMILY=%s\n", 30144d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_af2str(route->rt_family, buf, sizeof(buf))); 30244d362409d5469aed47d19e7908d19bd194493aThomas Graf 30344d362409d5469aed47d19e7908d19bd194493aThomas Graf if (route->ce_mask & ROUTE_ATTR_DST) 304535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump_line(p, "ROUTE_DST=%s\n", 30544d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_addr2str(route->rt_dst, buf, sizeof(buf))); 30644d362409d5469aed47d19e7908d19bd194493aThomas Graf 30744d362409d5469aed47d19e7908d19bd194493aThomas Graf if (route->ce_mask & ROUTE_ATTR_SRC) 308535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump_line(p, "ROUTE_SRC=%s\n", 30944d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_addr2str(route->rt_src, buf, sizeof(buf))); 31044d362409d5469aed47d19e7908d19bd194493aThomas Graf 31144d362409d5469aed47d19e7908d19bd194493aThomas Graf if (route->ce_mask & ROUTE_ATTR_PREF_SRC) 312535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump_line(p, "ROUTE_PREFSRC=%s\n", 31344d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_addr2str(route->rt_pref_src, buf, sizeof(buf))); 31444d362409d5469aed47d19e7908d19bd194493aThomas Graf 315d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf if (route->ce_mask & ROUTE_ATTR_IIF) { 316d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf if (link_cache) { 317d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf nl_dump_line(p, "ROUTE_IIF=%s", 318d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf rtnl_link_i2name(link_cache, route->rt_iif, 319d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf buf, sizeof(buf))); 320d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf } else 321d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf nl_dump_line(p, "ROUTE_IIF=%d", route->rt_iif); 322d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf } 32344d362409d5469aed47d19e7908d19bd194493aThomas Graf 32444d362409d5469aed47d19e7908d19bd194493aThomas Graf if (route->ce_mask & ROUTE_ATTR_TOS) 325535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump_line(p, "ROUTE_TOS=%u\n", route->rt_tos); 32644d362409d5469aed47d19e7908d19bd194493aThomas Graf 32744d362409d5469aed47d19e7908d19bd194493aThomas Graf if (route->ce_mask & ROUTE_ATTR_TABLE) 328535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump_line(p, "ROUTE_TABLE=%u\n", 32944d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_table); 33044d362409d5469aed47d19e7908d19bd194493aThomas Graf 33144d362409d5469aed47d19e7908d19bd194493aThomas Graf if (route->ce_mask & ROUTE_ATTR_SCOPE) 332535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump_line(p, "ROUTE_SCOPE=%s\n", 33344d362409d5469aed47d19e7908d19bd194493aThomas Graf rtnl_scope2str(route->rt_scope, buf, sizeof(buf))); 33444d362409d5469aed47d19e7908d19bd194493aThomas Graf 33544d362409d5469aed47d19e7908d19bd194493aThomas Graf if (route->ce_mask & ROUTE_ATTR_PRIO) 336535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump_line(p, "ROUTE_PRIORITY=%u\n", 33744d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_prio); 33844d362409d5469aed47d19e7908d19bd194493aThomas Graf 33944d362409d5469aed47d19e7908d19bd194493aThomas Graf if (route->ce_mask & ROUTE_ATTR_TYPE) 340535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump_line(p, "ROUTE_TYPE=%s\n", 34144d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_rtntype2str(route->rt_type, buf, sizeof(buf))); 34244d362409d5469aed47d19e7908d19bd194493aThomas Graf 343535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (route->ce_mask & ROUTE_ATTR_MULTIPATH) { 344535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct rtnl_nexthop *nh; 345535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf int index = 1; 34644d362409d5469aed47d19e7908d19bd194493aThomas Graf 347535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (route->rt_nr_nh > 0) 348535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_dump_line(p, "ROUTE_NR_NH=%u\n", route->rt_nr_nh); 34944d362409d5469aed47d19e7908d19bd194493aThomas Graf 350535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) { 351535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf p->dp_ivar = index++; 352535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnl_route_nh_dump(nh, p); 353535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 35444d362409d5469aed47d19e7908d19bd194493aThomas Graf } 35544d362409d5469aed47d19e7908d19bd194493aThomas Graf} 35644d362409d5469aed47d19e7908d19bd194493aThomas Graf 35744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int route_compare(struct nl_object *_a, struct nl_object *_b, 35844d362409d5469aed47d19e7908d19bd194493aThomas Graf uint32_t attrs, int flags) 35944d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 36044d362409d5469aed47d19e7908d19bd194493aThomas Graf struct rtnl_route *a = (struct rtnl_route *) _a; 36144d362409d5469aed47d19e7908d19bd194493aThomas Graf struct rtnl_route *b = (struct rtnl_route *) _b; 362535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct rtnl_nexthop *nh_a, *nh_b; 363535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf int i, diff = 0, found; 36444d362409d5469aed47d19e7908d19bd194493aThomas Graf 36544d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ROUTE_ATTR_##ATTR, a, b, EXPR) 36644d362409d5469aed47d19e7908d19bd194493aThomas Graf 36744d362409d5469aed47d19e7908d19bd194493aThomas Graf diff |= ROUTE_DIFF(FAMILY, a->rt_family != b->rt_family); 36844d362409d5469aed47d19e7908d19bd194493aThomas Graf diff |= ROUTE_DIFF(TOS, a->rt_tos != b->rt_tos); 36944d362409d5469aed47d19e7908d19bd194493aThomas Graf diff |= ROUTE_DIFF(TABLE, a->rt_table != b->rt_table); 37044d362409d5469aed47d19e7908d19bd194493aThomas Graf diff |= ROUTE_DIFF(PROTOCOL, a->rt_protocol != b->rt_protocol); 37144d362409d5469aed47d19e7908d19bd194493aThomas Graf diff |= ROUTE_DIFF(SCOPE, a->rt_scope != b->rt_scope); 37244d362409d5469aed47d19e7908d19bd194493aThomas Graf diff |= ROUTE_DIFF(TYPE, a->rt_type != b->rt_type); 37344d362409d5469aed47d19e7908d19bd194493aThomas Graf diff |= ROUTE_DIFF(PRIO, a->rt_prio != b->rt_prio); 37444d362409d5469aed47d19e7908d19bd194493aThomas Graf diff |= ROUTE_DIFF(DST, nl_addr_cmp(a->rt_dst, b->rt_dst)); 37544d362409d5469aed47d19e7908d19bd194493aThomas Graf diff |= ROUTE_DIFF(SRC, nl_addr_cmp(a->rt_src, b->rt_src)); 376535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf diff |= ROUTE_DIFF(IIF, a->rt_iif != b->rt_iif); 37744d362409d5469aed47d19e7908d19bd194493aThomas Graf diff |= ROUTE_DIFF(PREF_SRC, nl_addr_cmp(a->rt_pref_src, 37844d362409d5469aed47d19e7908d19bd194493aThomas Graf b->rt_pref_src)); 37944d362409d5469aed47d19e7908d19bd194493aThomas Graf 380535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (flags & LOOSE_COMPARISON) { 381535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) { 382535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf found = 0; 383535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_list_for_each_entry(nh_a, &a->rt_nexthops, 384535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnh_list) { 385535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (!rtnl_route_nh_compare(nh_a, nh_b, 386535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nh_b->ce_mask, 1)) { 387535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf found = 1; 388535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf break; 389535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 390535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 391535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 392535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (!found) 393535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto nh_mismatch; 394535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 395535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 39648e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf for (i = 0; i < RTAX_MAX - 1; i++) { 39748e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf if (a->rt_metrics_mask & (1 << i) && 39848e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf (!(b->rt_metrics_mask & (1 << i)) || 39948e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf a->rt_metrics[i] != b->rt_metrics[i])) 40048e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf ROUTE_DIFF(METRICS, 1); 401535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 40244d362409d5469aed47d19e7908d19bd194493aThomas Graf 40344d362409d5469aed47d19e7908d19bd194493aThomas Graf diff |= ROUTE_DIFF(FLAGS, 40444d362409d5469aed47d19e7908d19bd194493aThomas Graf (a->rt_flags ^ b->rt_flags) & b->rt_flag_mask); 405535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } else { 406535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (a->rt_nr_nh != a->rt_nr_nh) 407535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto nh_mismatch; 408535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 409535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf /* search for a dup in each nh of a */ 410535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_list_for_each_entry(nh_a, &a->rt_nexthops, rtnh_list) { 411535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf found = 0; 412535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_list_for_each_entry(nh_b, &b->rt_nexthops, 413535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnh_list) { 414535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0)) 415535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf found = 1; 416535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf break; 417535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 418535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (!found) 419535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto nh_mismatch; 420535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 421535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 422535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf /* search for a dup in each nh of b, covers case where a has 423535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * dupes itself */ 424535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) { 425535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf found = 0; 426535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_list_for_each_entry(nh_a, &a->rt_nexthops, 427535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnh_list) { 428535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0)) 429535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf found = 1; 430535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf break; 431535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 432535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (!found) 433535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto nh_mismatch; 434535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 435535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 43648e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf for (i = 0; i < RTAX_MAX - 1; i++) { 43748e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf if ((a->rt_metrics_mask & (1 << i)) ^ 43848e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf (b->rt_metrics_mask & (1 << i))) 439535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf diff |= ROUTE_DIFF(METRICS, 1); 440535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf else 44148e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf diff |= ROUTE_DIFF(METRICS, 44248e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf a->rt_metrics[i] != b->rt_metrics[i]); 443535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 444535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 44544d362409d5469aed47d19e7908d19bd194493aThomas Graf diff |= ROUTE_DIFF(FLAGS, a->rt_flags != b->rt_flags); 446535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 44744d362409d5469aed47d19e7908d19bd194493aThomas Graf 448535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafout: 44944d362409d5469aed47d19e7908d19bd194493aThomas Graf return diff; 450535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 451535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafnh_mismatch: 452535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf diff |= ROUTE_DIFF(MULTIPATH, 1); 453535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto out; 454535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 455535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf#undef ROUTE_DIFF 45644d362409d5469aed47d19e7908d19bd194493aThomas Graf} 45744d362409d5469aed47d19e7908d19bd194493aThomas Graf 45844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct trans_tbl route_attrs[] = { 45944d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_FAMILY, family) 46044d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_TOS, tos) 46144d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_TABLE, table) 46244d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_PROTOCOL, protocol) 46344d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_SCOPE, scope) 46444d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_TYPE, type) 46544d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_FLAGS, flags) 46644d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_DST, dst) 46744d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_SRC, src) 46844d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_IIF, iif) 46944d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_OIF, oif) 47044d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_GATEWAY, gateway) 47144d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_PRIO, prio) 47244d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_PREF_SRC, pref_src) 47344d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_METRICS, metrics) 47444d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_MULTIPATH, multipath) 47544d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_REALMS, realms) 47644d362409d5469aed47d19e7908d19bd194493aThomas Graf __ADD(ROUTE_ATTR_CACHEINFO, cacheinfo) 47744d362409d5469aed47d19e7908d19bd194493aThomas Graf}; 47844d362409d5469aed47d19e7908d19bd194493aThomas Graf 47944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic char *route_attrs2str(int attrs, char *buf, size_t len) 48044d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 48144d362409d5469aed47d19e7908d19bd194493aThomas Graf return __flags2str(attrs, buf, len, route_attrs, 48244d362409d5469aed47d19e7908d19bd194493aThomas Graf ARRAY_SIZE(route_attrs)); 48344d362409d5469aed47d19e7908d19bd194493aThomas Graf} 48444d362409d5469aed47d19e7908d19bd194493aThomas Graf 48544d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 48644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Allocation/Freeing 48744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{ 48844d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 48944d362409d5469aed47d19e7908d19bd194493aThomas Graf 49044d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct rtnl_route *rtnl_route_alloc(void) 49144d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 49244d362409d5469aed47d19e7908d19bd194493aThomas Graf return (struct rtnl_route *) nl_object_alloc(&route_obj_ops); 49344d362409d5469aed47d19e7908d19bd194493aThomas Graf} 49444d362409d5469aed47d19e7908d19bd194493aThomas Graf 49544d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_get(struct rtnl_route *route) 49644d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 49744d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_object_get((struct nl_object *) route); 49844d362409d5469aed47d19e7908d19bd194493aThomas Graf} 49944d362409d5469aed47d19e7908d19bd194493aThomas Graf 50044d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_put(struct rtnl_route *route) 50144d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 50244d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_object_put((struct nl_object *) route); 50344d362409d5469aed47d19e7908d19bd194493aThomas Graf} 50444d362409d5469aed47d19e7908d19bd194493aThomas Graf 50544d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */ 50644d362409d5469aed47d19e7908d19bd194493aThomas Graf 50744d362409d5469aed47d19e7908d19bd194493aThomas Graf/** 50844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Attributes 50944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{ 51044d362409d5469aed47d19e7908d19bd194493aThomas Graf */ 51144d362409d5469aed47d19e7908d19bd194493aThomas Graf 512535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_set_table(struct rtnl_route *route, uint32_t table) 51344d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 51444d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_table = table; 51544d362409d5469aed47d19e7908d19bd194493aThomas Graf route->ce_mask |= ROUTE_ATTR_TABLE; 51644d362409d5469aed47d19e7908d19bd194493aThomas Graf} 51744d362409d5469aed47d19e7908d19bd194493aThomas Graf 518535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafuint32_t rtnl_route_get_table(struct rtnl_route *route) 51944d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 520535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf return route->rt_table; 52144d362409d5469aed47d19e7908d19bd194493aThomas Graf} 52244d362409d5469aed47d19e7908d19bd194493aThomas Graf 523535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_set_scope(struct rtnl_route *route, uint8_t scope) 52444d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 52544d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_scope = scope; 52644d362409d5469aed47d19e7908d19bd194493aThomas Graf route->ce_mask |= ROUTE_ATTR_SCOPE; 52744d362409d5469aed47d19e7908d19bd194493aThomas Graf} 52844d362409d5469aed47d19e7908d19bd194493aThomas Graf 529535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafuint8_t rtnl_route_get_scope(struct rtnl_route *route) 53044d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 531535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf return route->rt_scope; 53244d362409d5469aed47d19e7908d19bd194493aThomas Graf} 53344d362409d5469aed47d19e7908d19bd194493aThomas Graf 534535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_set_tos(struct rtnl_route *route, uint8_t tos) 53544d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 53644d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_tos = tos; 53744d362409d5469aed47d19e7908d19bd194493aThomas Graf route->ce_mask |= ROUTE_ATTR_TOS; 53844d362409d5469aed47d19e7908d19bd194493aThomas Graf} 53944d362409d5469aed47d19e7908d19bd194493aThomas Graf 540535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafuint8_t rtnl_route_get_tos(struct rtnl_route *route) 54144d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 54244d362409d5469aed47d19e7908d19bd194493aThomas Graf return route->rt_tos; 54344d362409d5469aed47d19e7908d19bd194493aThomas Graf} 54444d362409d5469aed47d19e7908d19bd194493aThomas Graf 545535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_set_protocol(struct rtnl_route *route, uint8_t protocol) 54644d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 547535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->rt_protocol = protocol; 54844d362409d5469aed47d19e7908d19bd194493aThomas Graf route->ce_mask |= ROUTE_ATTR_PROTOCOL; 54944d362409d5469aed47d19e7908d19bd194493aThomas Graf} 55044d362409d5469aed47d19e7908d19bd194493aThomas Graf 551535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafuint8_t rtnl_route_get_protocol(struct rtnl_route *route) 55244d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 553535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf return route->rt_protocol; 55444d362409d5469aed47d19e7908d19bd194493aThomas Graf} 55544d362409d5469aed47d19e7908d19bd194493aThomas Graf 556535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_set_priority(struct rtnl_route *route, uint32_t prio) 55744d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 55844d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_prio = prio; 55944d362409d5469aed47d19e7908d19bd194493aThomas Graf route->ce_mask |= ROUTE_ATTR_PRIO; 56044d362409d5469aed47d19e7908d19bd194493aThomas Graf} 56144d362409d5469aed47d19e7908d19bd194493aThomas Graf 562535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafuint32_t rtnl_route_get_priority(struct rtnl_route *route) 56344d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 56444d362409d5469aed47d19e7908d19bd194493aThomas Graf return route->rt_prio; 56544d362409d5469aed47d19e7908d19bd194493aThomas Graf} 56644d362409d5469aed47d19e7908d19bd194493aThomas Graf 567535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafint rtnl_route_set_family(struct rtnl_route *route, uint8_t family) 56844d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 569535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (family != AF_INET && family != AF_INET6 && family != AF_DECnet) 5708a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_AF_NOSUPPORT; 571535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 57244d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_family = family; 57344d362409d5469aed47d19e7908d19bd194493aThomas Graf route->ce_mask |= ROUTE_ATTR_FAMILY; 574535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 575535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf return 0; 57644d362409d5469aed47d19e7908d19bd194493aThomas Graf} 57744d362409d5469aed47d19e7908d19bd194493aThomas Graf 578535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafuint8_t rtnl_route_get_family(struct rtnl_route *route) 57944d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 580535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf return route->rt_family; 58144d362409d5469aed47d19e7908d19bd194493aThomas Graf} 58244d362409d5469aed47d19e7908d19bd194493aThomas Graf 58344d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_set_dst(struct rtnl_route *route, struct nl_addr *addr) 58444d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 58544d362409d5469aed47d19e7908d19bd194493aThomas Graf if (route->ce_mask & ROUTE_ATTR_FAMILY) { 58644d362409d5469aed47d19e7908d19bd194493aThomas Graf if (addr->a_family != route->rt_family) 5878a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_AF_MISMATCH; 58844d362409d5469aed47d19e7908d19bd194493aThomas Graf } else 58944d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_family = addr->a_family; 59044d362409d5469aed47d19e7908d19bd194493aThomas Graf 59144d362409d5469aed47d19e7908d19bd194493aThomas Graf if (route->rt_dst) 59244d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_addr_put(route->rt_dst); 59344d362409d5469aed47d19e7908d19bd194493aThomas Graf 59444d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_addr_get(addr); 59544d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_dst = addr; 59644d362409d5469aed47d19e7908d19bd194493aThomas Graf 59744d362409d5469aed47d19e7908d19bd194493aThomas Graf route->ce_mask |= (ROUTE_ATTR_DST | ROUTE_ATTR_FAMILY); 59844d362409d5469aed47d19e7908d19bd194493aThomas Graf 59944d362409d5469aed47d19e7908d19bd194493aThomas Graf return 0; 60044d362409d5469aed47d19e7908d19bd194493aThomas Graf} 60144d362409d5469aed47d19e7908d19bd194493aThomas Graf 60244d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *rtnl_route_get_dst(struct rtnl_route *route) 60344d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 60444d362409d5469aed47d19e7908d19bd194493aThomas Graf return route->rt_dst; 60544d362409d5469aed47d19e7908d19bd194493aThomas Graf} 60644d362409d5469aed47d19e7908d19bd194493aThomas Graf 60744d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_set_src(struct rtnl_route *route, struct nl_addr *addr) 60844d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 609535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (addr->a_family == AF_INET) 6108a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_SRCRT_NOSUPPORT; 611535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 61244d362409d5469aed47d19e7908d19bd194493aThomas Graf if (route->ce_mask & ROUTE_ATTR_FAMILY) { 61344d362409d5469aed47d19e7908d19bd194493aThomas Graf if (addr->a_family != route->rt_family) 6148a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_AF_MISMATCH; 61544d362409d5469aed47d19e7908d19bd194493aThomas Graf } else 61644d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_family = addr->a_family; 61744d362409d5469aed47d19e7908d19bd194493aThomas Graf 61844d362409d5469aed47d19e7908d19bd194493aThomas Graf if (route->rt_src) 61944d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_addr_put(route->rt_src); 62044d362409d5469aed47d19e7908d19bd194493aThomas Graf 62144d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_addr_get(addr); 62244d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_src = addr; 62344d362409d5469aed47d19e7908d19bd194493aThomas Graf route->ce_mask |= (ROUTE_ATTR_SRC | ROUTE_ATTR_FAMILY); 62444d362409d5469aed47d19e7908d19bd194493aThomas Graf 62544d362409d5469aed47d19e7908d19bd194493aThomas Graf return 0; 62644d362409d5469aed47d19e7908d19bd194493aThomas Graf} 62744d362409d5469aed47d19e7908d19bd194493aThomas Graf 62844d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *rtnl_route_get_src(struct rtnl_route *route) 62944d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 63044d362409d5469aed47d19e7908d19bd194493aThomas Graf return route->rt_src; 63144d362409d5469aed47d19e7908d19bd194493aThomas Graf} 63244d362409d5469aed47d19e7908d19bd194493aThomas Graf 633535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafint rtnl_route_set_type(struct rtnl_route *route, uint8_t type) 63444d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 635535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (type > RTN_MAX) 6368a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_RANGE; 6378a3efffa5b3fde252675239914118664d36a2c24Thomas Graf 63844d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_type = type; 63944d362409d5469aed47d19e7908d19bd194493aThomas Graf route->ce_mask |= ROUTE_ATTR_TYPE; 640535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 641535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf return 0; 64244d362409d5469aed47d19e7908d19bd194493aThomas Graf} 64344d362409d5469aed47d19e7908d19bd194493aThomas Graf 644535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafuint8_t rtnl_route_get_type(struct rtnl_route *route) 64544d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 646535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf return route->rt_type; 64744d362409d5469aed47d19e7908d19bd194493aThomas Graf} 64844d362409d5469aed47d19e7908d19bd194493aThomas Graf 649535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_set_flags(struct rtnl_route *route, uint32_t flags) 65044d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 65144d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_flag_mask |= flags; 65244d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_flags |= flags; 65344d362409d5469aed47d19e7908d19bd194493aThomas Graf route->ce_mask |= ROUTE_ATTR_FLAGS; 65444d362409d5469aed47d19e7908d19bd194493aThomas Graf} 65544d362409d5469aed47d19e7908d19bd194493aThomas Graf 656535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_unset_flags(struct rtnl_route *route, uint32_t flags) 65744d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 65844d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_flag_mask |= flags; 65944d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_flags &= ~flags; 66044d362409d5469aed47d19e7908d19bd194493aThomas Graf route->ce_mask |= ROUTE_ATTR_FLAGS; 66144d362409d5469aed47d19e7908d19bd194493aThomas Graf} 66244d362409d5469aed47d19e7908d19bd194493aThomas Graf 663535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafuint32_t rtnl_route_get_flags(struct rtnl_route *route) 66444d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 66544d362409d5469aed47d19e7908d19bd194493aThomas Graf return route->rt_flags; 66644d362409d5469aed47d19e7908d19bd194493aThomas Graf} 66744d362409d5469aed47d19e7908d19bd194493aThomas Graf 66844d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value) 66944d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 67044d362409d5469aed47d19e7908d19bd194493aThomas Graf if (metric > RTAX_MAX || metric < 1) 6718a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_RANGE; 67244d362409d5469aed47d19e7908d19bd194493aThomas Graf 67344d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_metrics[metric - 1] = value; 674535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 675535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (!(route->rt_metrics_mask & (1 << (metric - 1)))) { 676535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->rt_nmetrics++; 677535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->rt_metrics_mask |= (1 << (metric - 1)); 678535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 679535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 680535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->ce_mask |= ROUTE_ATTR_METRICS; 68144d362409d5469aed47d19e7908d19bd194493aThomas Graf 68244d362409d5469aed47d19e7908d19bd194493aThomas Graf return 0; 68344d362409d5469aed47d19e7908d19bd194493aThomas Graf} 68444d362409d5469aed47d19e7908d19bd194493aThomas Graf 68544d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_unset_metric(struct rtnl_route *route, int metric) 68644d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 68744d362409d5469aed47d19e7908d19bd194493aThomas Graf if (metric > RTAX_MAX || metric < 1) 6888a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_RANGE; 68944d362409d5469aed47d19e7908d19bd194493aThomas Graf 690535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (route->rt_metrics_mask & (1 << (metric - 1))) { 691535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->rt_nmetrics--; 692535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->rt_metrics_mask &= ~(1 << (metric - 1)); 693535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 69444d362409d5469aed47d19e7908d19bd194493aThomas Graf 69544d362409d5469aed47d19e7908d19bd194493aThomas Graf return 0; 69644d362409d5469aed47d19e7908d19bd194493aThomas Graf} 69744d362409d5469aed47d19e7908d19bd194493aThomas Graf 698535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafint rtnl_route_get_metric(struct rtnl_route *route, int metric, uint32_t *value) 69944d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 70044d362409d5469aed47d19e7908d19bd194493aThomas Graf if (metric > RTAX_MAX || metric < 1) 7018a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_RANGE; 70244d362409d5469aed47d19e7908d19bd194493aThomas Graf 70344d362409d5469aed47d19e7908d19bd194493aThomas Graf if (!(route->rt_metrics_mask & (1 << (metric - 1)))) 7048a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_OBJ_NOTFOUND; 705535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 706535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (value) 707535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf *value = route->rt_metrics[metric - 1]; 70844d362409d5469aed47d19e7908d19bd194493aThomas Graf 709535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf return 0; 71044d362409d5469aed47d19e7908d19bd194493aThomas Graf} 71144d362409d5469aed47d19e7908d19bd194493aThomas Graf 71244d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_set_pref_src(struct rtnl_route *route, struct nl_addr *addr) 71344d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 71444d362409d5469aed47d19e7908d19bd194493aThomas Graf if (route->ce_mask & ROUTE_ATTR_FAMILY) { 71544d362409d5469aed47d19e7908d19bd194493aThomas Graf if (addr->a_family != route->rt_family) 7168a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_AF_MISMATCH; 71744d362409d5469aed47d19e7908d19bd194493aThomas Graf } else 71844d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_family = addr->a_family; 71944d362409d5469aed47d19e7908d19bd194493aThomas Graf 72044d362409d5469aed47d19e7908d19bd194493aThomas Graf if (route->rt_pref_src) 72144d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_addr_put(route->rt_pref_src); 72244d362409d5469aed47d19e7908d19bd194493aThomas Graf 72344d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_addr_get(addr); 72444d362409d5469aed47d19e7908d19bd194493aThomas Graf route->rt_pref_src = addr; 72544d362409d5469aed47d19e7908d19bd194493aThomas Graf route->ce_mask |= (ROUTE_ATTR_PREF_SRC | ROUTE_ATTR_FAMILY); 72644d362409d5469aed47d19e7908d19bd194493aThomas Graf 72744d362409d5469aed47d19e7908d19bd194493aThomas Graf return 0; 72844d362409d5469aed47d19e7908d19bd194493aThomas Graf} 72944d362409d5469aed47d19e7908d19bd194493aThomas Graf 73044d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *route) 73144d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 73244d362409d5469aed47d19e7908d19bd194493aThomas Graf return route->rt_pref_src; 73344d362409d5469aed47d19e7908d19bd194493aThomas Graf} 73444d362409d5469aed47d19e7908d19bd194493aThomas Graf 735535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_set_iif(struct rtnl_route *route, int ifindex) 73644d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 737535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->rt_iif = ifindex; 73844d362409d5469aed47d19e7908d19bd194493aThomas Graf route->ce_mask |= ROUTE_ATTR_IIF; 73944d362409d5469aed47d19e7908d19bd194493aThomas Graf} 74044d362409d5469aed47d19e7908d19bd194493aThomas Graf 741535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafint rtnl_route_get_iif(struct rtnl_route *route) 74244d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 743535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf return route->rt_iif; 74444d362409d5469aed47d19e7908d19bd194493aThomas Graf} 74544d362409d5469aed47d19e7908d19bd194493aThomas Graf 74644d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_add_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh) 74744d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 74844d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_list_add_tail(&nh->rtnh_list, &route->rt_nexthops); 749535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->rt_nr_nh++; 75044d362409d5469aed47d19e7908d19bd194493aThomas Graf route->ce_mask |= ROUTE_ATTR_MULTIPATH; 75144d362409d5469aed47d19e7908d19bd194493aThomas Graf} 75244d362409d5469aed47d19e7908d19bd194493aThomas Graf 753535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_remove_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh) 75444d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 755535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->rt_nr_nh--; 75644d362409d5469aed47d19e7908d19bd194493aThomas Graf nl_list_del(&nh->rtnh_list); 75744d362409d5469aed47d19e7908d19bd194493aThomas Graf} 75844d362409d5469aed47d19e7908d19bd194493aThomas Graf 75944d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *route) 76044d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 76144d362409d5469aed47d19e7908d19bd194493aThomas Graf return &route->rt_nexthops; 76244d362409d5469aed47d19e7908d19bd194493aThomas Graf} 76344d362409d5469aed47d19e7908d19bd194493aThomas Graf 764535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafint rtnl_route_get_nnexthops(struct rtnl_route *route) 76544d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 766535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf return route->rt_nr_nh; 76744d362409d5469aed47d19e7908d19bd194493aThomas Graf} 76844d362409d5469aed47d19e7908d19bd194493aThomas Graf 769cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsavoid rtnl_route_foreach_nexthop(struct rtnl_route *r, 770cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa void (*cb)(struct rtnl_nexthop *, void *), 771cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa void *arg) 772cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa{ 773cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa struct rtnl_nexthop *nh; 774cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa 775cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa if (r->ce_mask & ROUTE_ATTR_MULTIPATH) { 776cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) { 777cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa cb(nh, arg); 778cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa } 779cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa } 780cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa} 781cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa 782cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsastruct rtnl_nexthop *rtnl_route_nexthop_n(struct rtnl_route *r, int n) 783cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa{ 784cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa struct rtnl_nexthop *nh; 785cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa int i; 786cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa 787cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa if (r->ce_mask & ROUTE_ATTR_MULTIPATH && r->rt_nr_nh > n) { 788cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa i = 0; 789cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) { 790cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa if (i == n) return nh; 791cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa i++; 792cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa } 793cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa } 794cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa return NULL; 795cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa} 796cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa 797535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf/** @} */ 798535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 799535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf/** 800535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * @name Utilities 801535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * @{ 802535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf */ 803535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 804535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf/** 805535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * Guess scope of a route object. 806535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * @arg route Route object. 807535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * 808535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * Guesses the scope of a route object, based on the following rules: 809535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * @code 810535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * 1) Local route -> local scope 811535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * 2) At least one nexthop not directly connected -> universe scope 812535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * 3) All others -> link scope 813535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * @endcode 814535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * 815535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * @return Scope value. 816535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf */ 817535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafint rtnl_route_guess_scope(struct rtnl_route *route) 81844d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 819535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (route->rt_type == RTN_LOCAL) 820535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf return RT_SCOPE_HOST; 821535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 822535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (!nl_list_empty(&route->rt_nexthops)) { 823535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct rtnl_nexthop *nh; 824535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 825535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf /* 826535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * Use scope uiniverse if there is at least one nexthop which 827535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * is not directly connected 828535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf */ 829535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) { 830535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (nh->rtnh_gateway) 831535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf return RT_SCOPE_UNIVERSE; 832535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 833535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 834535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 835535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf return RT_SCOPE_LINK; 83644d362409d5469aed47d19e7908d19bd194493aThomas Graf} 83744d362409d5469aed47d19e7908d19bd194493aThomas Graf 838535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf/** @} */ 839535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 840535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafstatic struct nla_policy route_policy[RTA_MAX+1] = { 841535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf [RTA_IIF] = { .type = NLA_U32 }, 842535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf [RTA_OIF] = { .type = NLA_U32 }, 843535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf [RTA_PRIORITY] = { .type = NLA_U32 }, 844535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf [RTA_FLOW] = { .type = NLA_U32 }, 845535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) }, 846535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf [RTA_METRICS] = { .type = NLA_NESTED }, 847535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf [RTA_MULTIPATH] = { .type = NLA_NESTED }, 848535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf}; 849535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 850eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Grafstatic int parse_multipath(struct rtnl_route *route, struct nlattr *attr) 851eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf{ 852eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf struct rtnl_nexthop *nh = NULL; 853eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf struct rtnexthop *rtnh = nla_data(attr); 854eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf size_t tlen = nla_len(attr); 855eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf int err; 856eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf 857eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) { 858eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf nh = rtnl_route_nh_alloc(); 859eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf if (!nh) 860eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf return -NLE_NOMEM; 861eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf 862eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops); 863eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex); 864eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags); 865eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf 866eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf if (rtnh->rtnh_len > sizeof(*rtnh)) { 867eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf struct nlattr *ntb[RTA_MAX + 1]; 868eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf 869eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf err = nla_parse(ntb, RTA_MAX, (struct nlattr *) 870eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf RTNH_DATA(rtnh), 871eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf rtnh->rtnh_len - sizeof(*rtnh), 872eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf route_policy); 873eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf if (err < 0) 874eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf goto errout; 875eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf 876eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf if (ntb[RTA_GATEWAY]) { 877eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf struct nl_addr *addr; 878eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf 879eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf addr = nl_addr_alloc_attr(ntb[RTA_GATEWAY], 880eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf route->rt_family); 881eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf if (!addr) { 882eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf err = -NLE_NOMEM; 883eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf goto errout; 884eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf } 885eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf 886eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf rtnl_route_nh_set_gateway(nh, addr); 887eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf nl_addr_put(addr); 888eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf } 889eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf 890eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf if (ntb[RTA_FLOW]) { 891eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf uint32_t realms; 892eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf 893eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf realms = nla_get_u32(ntb[RTA_FLOW]); 894eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf rtnl_route_nh_set_realms(nh, realms); 895eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf } 896eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf } 897eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf 898eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf rtnl_route_add_nexthop(route, nh); 899eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf tlen -= RTNH_ALIGN(rtnh->rtnh_len); 900eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf rtnh = RTNH_NEXT(rtnh); 901eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf } 902eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf 903eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf err = 0; 904eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graferrout: 905eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf if (err && nh) 906eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf rtnl_route_nh_free(nh); 907eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf 908eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf return err; 909eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf} 910eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf 9118a3efffa5b3fde252675239914118664d36a2c24Thomas Grafint rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result) 91244d362409d5469aed47d19e7908d19bd194493aThomas Graf{ 913535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct rtmsg *rtm; 914535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct rtnl_route *route; 915535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct nlattr *tb[RTA_MAX + 1]; 916535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct nl_addr *src = NULL, *dst = NULL, *addr; 917535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct rtnl_nexthop *old_nh = NULL; 918eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf int err, family; 919535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 920535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route = rtnl_route_alloc(); 921535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (!route) { 9228a3efffa5b3fde252675239914118664d36a2c24Thomas Graf err = -NLE_NOMEM; 923535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto errout; 924535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 925535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 926535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->ce_msgtype = nlh->nlmsg_type; 927535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 928535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, route_policy); 929535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (err < 0) 930535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto errout; 931535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 932535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtm = nlmsg_data(nlh); 933eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf route->rt_family = family = rtm->rtm_family; 934535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->rt_tos = rtm->rtm_tos; 935535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->rt_table = rtm->rtm_table; 936535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->rt_type = rtm->rtm_type; 937535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->rt_scope = rtm->rtm_scope; 938535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->rt_protocol = rtm->rtm_protocol; 939535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->rt_flags = rtm->rtm_flags; 940535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 941535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->ce_mask |= ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS | 942535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf ROUTE_ATTR_TABLE | ROUTE_ATTR_TYPE | 943535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf ROUTE_ATTR_SCOPE | ROUTE_ATTR_PROTOCOL | 944535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf ROUTE_ATTR_FLAGS; 945535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 946535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (tb[RTA_DST]) { 947eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf if (!(dst = nl_addr_alloc_attr(tb[RTA_DST], family))) 948eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf goto errout_nomem; 949535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } else { 950eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf if (!(dst = nl_addr_alloc(0))) 951eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf goto errout_nomem; 952535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_addr_set_family(dst, rtm->rtm_family); 953535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 954535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 955535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_addr_set_prefixlen(dst, rtm->rtm_dst_len); 956535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf err = rtnl_route_set_dst(route, dst); 957535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (err < 0) 958535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto errout; 959535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 960535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_addr_put(dst); 961535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 962535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (tb[RTA_SRC]) { 963eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf if (!(src = nl_addr_alloc_attr(tb[RTA_SRC], family))) 964eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf goto errout_nomem; 965535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } else if (rtm->rtm_src_len) 966eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf if (!(src = nl_addr_alloc(0))) 967eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf goto errout_nomem; 968535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 969535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (src) { 970535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_addr_set_prefixlen(src, rtm->rtm_src_len); 971535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnl_route_set_src(route, src); 972535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_addr_put(src); 973535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 974535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 975535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (tb[RTA_IIF]) 976535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnl_route_set_iif(route, nla_get_u32(tb[RTA_IIF])); 977535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 978535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (tb[RTA_PRIORITY]) 979535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnl_route_set_priority(route, nla_get_u32(tb[RTA_PRIORITY])); 980535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 981535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (tb[RTA_PREFSRC]) { 982eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf if (!(addr = nl_addr_alloc_attr(tb[RTA_PREFSRC], family))) 983eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf goto errout_nomem; 984535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnl_route_set_pref_src(route, addr); 985535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_addr_put(addr); 986535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 987535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 988535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (tb[RTA_METRICS]) { 989535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct nlattr *mtb[RTAX_MAX + 1]; 990535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf int i; 991535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 992535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL); 993535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (err < 0) 994535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto errout; 995535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 996535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf for (i = 1; i <= RTAX_MAX; i++) { 997535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) { 998535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf uint32_t m = nla_get_u32(mtb[i]); 999535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (rtnl_route_set_metric(route, i, m) < 0) 1000535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto errout; 1001535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 1002535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 1003535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 1004535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1005eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf if (tb[RTA_MULTIPATH]) 1006eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf if ((err = parse_multipath(route, tb[RTA_MULTIPATH])) < 0) 1007eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf goto errout; 1008535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1009535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (tb[RTA_CACHEINFO]) { 1010535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nla_memcpy(&route->rt_cacheinfo, tb[RTA_CACHEINFO], 1011535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf sizeof(route->rt_cacheinfo)); 1012535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf route->ce_mask |= ROUTE_ATTR_CACHEINFO; 1013535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 1014535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1015535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (tb[RTA_OIF]) { 1016535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (!old_nh && !(old_nh = rtnl_route_nh_alloc())) 1017535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto errout; 1018535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1019535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnl_route_nh_set_ifindex(old_nh, nla_get_u32(tb[RTA_OIF])); 1020535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 1021535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1022535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (tb[RTA_GATEWAY]) { 1023535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (!old_nh && !(old_nh = rtnl_route_nh_alloc())) 1024535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto errout; 1025535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1026eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf if (!(addr = nl_addr_alloc_attr(tb[RTA_GATEWAY], family))) 1027eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf goto errout_nomem; 1028535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1029535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnl_route_nh_set_gateway(old_nh, addr); 1030535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_addr_put(addr); 1031535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 1032535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1033535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (tb[RTA_FLOW]) { 1034535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (!old_nh && !(old_nh = rtnl_route_nh_alloc())) 1035535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto errout; 1036535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1037535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnl_route_nh_set_realms(old_nh, nla_get_u32(tb[RTA_FLOW])); 1038535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 1039535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1040535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (old_nh) { 1041535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (route->rt_nr_nh == 0) { 1042535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf /* If no nexthops have been provided via RTA_MULTIPATH 1043535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * we add it as regular nexthop to maintain backwards 1044535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * compatibility */ 1045535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnl_route_add_nexthop(route, old_nh); 1046535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } else { 1047535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf /* Kernel supports new style nexthop configuration, 1048535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * verify that it is a duplicate and discard nexthop. */ 1049535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct rtnl_nexthop *first; 1050535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1051535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf first = nl_list_first_entry(&route->rt_nexthops, 1052535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct rtnl_nexthop, 1053535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnh_list); 1054535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (!first) 1055535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf BUG(); 1056535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1057535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (rtnl_route_nh_compare(old_nh, first, 1058535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf old_nh->ce_mask, 0)) { 10598a3efffa5b3fde252675239914118664d36a2c24Thomas Graf err = -NLE_INVAL; 1060535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto errout; 1061535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 1062535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1063535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnl_route_nh_free(old_nh); 1064535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 1065535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 1066535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 10678a3efffa5b3fde252675239914118664d36a2c24Thomas Graf *result = route; 10688a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return 0; 1069535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1070535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graferrout: 1071535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnl_route_put(route); 10728a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return err; 1073eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf 1074eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graferrout_nomem: 1075eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf err = -NLE_NOMEM; 1076eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf goto errout; 107744d362409d5469aed47d19e7908d19bd194493aThomas Graf} 107844d362409d5469aed47d19e7908d19bd194493aThomas Graf 1079535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafint rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route) 1080535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf{ 1081535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf int i; 1082535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct nlattr *metrics; 1083535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct rtmsg rtmsg = { 1084535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf .rtm_family = route->rt_family, 1085535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf .rtm_tos = route->rt_tos, 1086535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf .rtm_table = route->rt_table, 1087535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf .rtm_protocol = route->rt_protocol, 1088535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf .rtm_scope = route->rt_scope, 1089535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf .rtm_type = route->rt_type, 1090535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf .rtm_flags = route->rt_flags, 1091535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf }; 1092535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1093535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (route->rt_dst == NULL) 10948a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_MISSING_ATTR; 1095535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1096535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtmsg.rtm_dst_len = nl_addr_get_prefixlen(route->rt_dst); 1097535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (route->rt_src) 1098535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtmsg.rtm_src_len = nl_addr_get_prefixlen(route->rt_src); 109944d362409d5469aed47d19e7908d19bd194493aThomas Graf 1100535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1101535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (rtmsg.rtm_scope == RT_SCOPE_NOWHERE) 1102535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtmsg.rtm_scope = rtnl_route_guess_scope(route); 1103535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1104535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0) 1105535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto nla_put_failure; 1106535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1107535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf /* Additional table attribute replacing the 8bit in the header, was 1108535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * required to allow more than 256 tables. */ 1109535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf NLA_PUT_U32(msg, RTA_TABLE, route->rt_table); 1110535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 11112b3fabab9ef2445ab1c48de0fed82514e4eb32dcDavid Lamparter if (nl_addr_get_len(route->rt_dst)) 11122b3fabab9ef2445ab1c48de0fed82514e4eb32dcDavid Lamparter NLA_PUT_ADDR(msg, RTA_DST, route->rt_dst); 1113535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf NLA_PUT_U32(msg, RTA_PRIORITY, route->rt_prio); 1114535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1115535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (route->ce_mask & ROUTE_ATTR_SRC) 1116535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf NLA_PUT_ADDR(msg, RTA_SRC, route->rt_src); 1117535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1118535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (route->ce_mask & ROUTE_ATTR_PREF_SRC) 1119535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf NLA_PUT_ADDR(msg, RTA_PREFSRC, route->rt_pref_src); 1120535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1121535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (route->ce_mask & ROUTE_ATTR_IIF) 1122535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf NLA_PUT_U32(msg, RTA_IIF, route->rt_iif); 1123535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1124535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (route->rt_nmetrics > 0) { 1125535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf uint32_t val; 1126535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1127535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf metrics = nla_nest_start(msg, RTA_METRICS); 1128535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (metrics == NULL) 1129535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto nla_put_failure; 1130535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1131535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf for (i = 1; i <= RTAX_MAX; i++) { 1132535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (!rtnl_route_get_metric(route, i, &val)) 1133535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf NLA_PUT_U32(msg, i, val); 1134535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 1135535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1136535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nla_nest_end(msg, metrics); 1137535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 1138535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1139535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (rtnl_route_get_nnexthops(route) > 0) { 1140535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct nlattr *multipath; 1141535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct rtnl_nexthop *nh; 1142535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1143535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (!(multipath = nla_nest_start(msg, RTA_MULTIPATH))) 1144535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto nla_put_failure; 1145535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1146535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) { 1147535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf struct rtnexthop *rtnh; 1148535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1149535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnh = nlmsg_reserve(msg, sizeof(*rtnh), NLMSG_ALIGNTO); 1150535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (!rtnh) 1151535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf goto nla_put_failure; 1152535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1153535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnh->rtnh_flags = nh->rtnh_flags; 1154535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnh->rtnh_hops = nh->rtnh_weight; 1155535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnh->rtnh_ifindex = nh->rtnh_ifindex; 1156535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1157535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (nh->rtnh_gateway) 1158535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf NLA_PUT_ADDR(msg, RTA_GATEWAY, 1159535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nh->rtnh_gateway); 1160535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1161535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf if (nh->rtnh_realms) 1162535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms); 1163535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1164535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf rtnh->rtnh_len = nlmsg_tail(msg->nm_nlh) - 1165535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf (void *) rtnh; 1166535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 1167535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1168535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf nla_nest_end(msg, multipath); 1169535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf } 1170535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1171535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf return 0; 1172535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1173535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafnla_put_failure: 11748a3efffa5b3fde252675239914118664d36a2c24Thomas Graf return -NLE_MSGSIZE; 1175535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf} 1176535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf 1177535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf/** @cond SKIP */ 117844d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_object_ops route_obj_ops = { 117944d362409d5469aed47d19e7908d19bd194493aThomas Graf .oo_name = "route/route", 118044d362409d5469aed47d19e7908d19bd194493aThomas Graf .oo_size = sizeof(struct rtnl_route), 118144d362409d5469aed47d19e7908d19bd194493aThomas Graf .oo_constructor = route_constructor, 118244d362409d5469aed47d19e7908d19bd194493aThomas Graf .oo_free_data = route_free_data, 118344d362409d5469aed47d19e7908d19bd194493aThomas Graf .oo_clone = route_clone, 1184d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf .oo_dump = { 1185d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf [NL_DUMP_LINE] = route_dump_line, 1186d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf [NL_DUMP_DETAILS] = route_dump_details, 1187d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf [NL_DUMP_STATS] = route_dump_stats, 1188d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf [NL_DUMP_ENV] = route_dump_env, 1189d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf }, 119044d362409d5469aed47d19e7908d19bd194493aThomas Graf .oo_compare = route_compare, 119144d362409d5469aed47d19e7908d19bd194493aThomas Graf .oo_attrs2str = route_attrs2str, 119244d362409d5469aed47d19e7908d19bd194493aThomas Graf .oo_id_attrs = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS | 119344d362409d5469aed47d19e7908d19bd194493aThomas Graf ROUTE_ATTR_TABLE | ROUTE_ATTR_DST), 119444d362409d5469aed47d19e7908d19bd194493aThomas Graf}; 1195535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf/** @endcond */ 119644d362409d5469aed47d19e7908d19bd194493aThomas Graf 119744d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */ 1198