FRA_UNUSED5,
FRA_FWMARK, /* netfilter mark (IPv4) */
FRA_FLOW, /* flow/class id */
+ FRA_UNUSED6,
+ FRA_UNUSED7,
+ FRA_UNUSED8,
+ FRA_TABLE, /* Extended table id */
__FRA_MAX
};
RTA_CACHEINFO,
RTA_SESSION,
RTA_MP_ALGO,
+ RTA_TABLE,
__RTA_MAX
};
} \
} while(0)
+static inline u32 rtm_get_table(struct rtattr **rta, u8 table)
+{
+ return RTA_GET_U32(rta[RTA_TABLE-1]);
+rtattr_failure:
+ return table;
+}
+
#endif /* __KERNEL__ */
call_rcu(&rule->rcu, fib_rule_put_rcu);
}
+static inline u32 frh_get_table(struct fib_rule_hdr *frh, struct nlattr **nla)
+{
+ if (nla[FRA_TABLE])
+ return nla_get_u32(nla[FRA_TABLE]);
+ return frh->table;
+}
+
extern int fib_rules_register(struct fib_rules_ops *);
extern int fib_rules_unregister(struct fib_rules_ops *);
rule->action = frh->action;
rule->flags = frh->flags;
- rule->table = frh->table;
+ rule->table = frh_get_table(frh, tb);
if (!rule->pref && ops->default_pref)
rule->pref = ops->default_pref();
if (frh->action && (frh->action != rule->action))
continue;
- if (frh->table && (frh->table != rule->table))
+ if (frh->table && (frh_get_table(frh, tb) != rule->table))
continue;
if (tb[FRA_PRIORITY] &&
frh = nlmsg_data(nlh);
frh->table = rule->table;
+ NLA_PUT_U32(skb, FRA_TABLE, rule->table);
frh->res1 = 0;
frh->res2 = 0;
frh->action = rule->action;
if (attr) {
if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2)
return -EINVAL;
- if (i != RTA_MULTIPATH && i != RTA_METRICS)
+ if (i != RTA_MULTIPATH && i != RTA_METRICS &&
+ i != RTA_TABLE)
rta[i-1] = (struct rtattr *)RTA_DATA(attr);
}
}
if (dn_fib_check_attr(r, rta))
return -EINVAL;
- tb = dn_fib_get_table(r->rtm_table, 0);
+ tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 0);
if (tb)
return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
if (dn_fib_check_attr(r, rta))
return -EINVAL;
- tb = dn_fib_get_table(r->rtm_table, 1);
+ tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 1);
if (tb)
return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
r->rtm_src_len = 0;
r->rtm_tos = 0;
r->rtm_table = RT_TABLE_MAIN;
+ RTA_PUT_U32(skb, RTA_TABLE, RT_TABLE_MAIN);
r->rtm_type = rt->rt_type;
r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED;
r->rtm_scope = RT_SCOPE_UNIVERSE;
rtm->rtm_src_len = 0;
rtm->rtm_tos = 0;
rtm->rtm_table = tb_id;
+ RTA_PUT_U32(skb, RTA_TABLE, tb_id);
rtm->rtm_flags = fi->fib_flags;
rtm->rtm_scope = scope;
rtm->rtm_type = type;
if (attr) {
if (RTA_PAYLOAD(attr) < 4)
return -EINVAL;
- if (i != RTA_MULTIPATH && i != RTA_METRICS)
+ if (i != RTA_MULTIPATH && i != RTA_METRICS &&
+ i != RTA_TABLE)
*rta = (struct rtattr*)RTA_DATA(attr);
}
}
if (inet_check_attr(r, rta))
return -EINVAL;
- tb = fib_get_table(r->rtm_table);
+ tb = fib_get_table(rtm_get_table(rta, r->rtm_table));
if (tb)
return tb->tb_delete(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb));
return -ESRCH;
if (inet_check_attr(r, rta))
return -EINVAL;
- tb = fib_new_table(r->rtm_table);
+ tb = fib_new_table(rtm_get_table(rta, r->rtm_table));
if (tb)
return tb->tb_insert(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb));
return -ENOBUFS;
[FRA_DST] = { .type = NLA_U32 },
[FRA_FWMARK] = { .type = NLA_U32 },
[FRA_FLOW] = { .type = NLA_U32 },
+ [FRA_TABLE] = { .type = NLA_U32 },
};
static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
rtm->rtm_src_len = 0;
rtm->rtm_tos = tos;
rtm->rtm_table = tb_id;
+ RTA_PUT_U32(skb, RTA_TABLE, tb_id);
rtm->rtm_type = type;
rtm->rtm_flags = fi->fib_flags;
rtm->rtm_scope = scope;
r->rtm_src_len = 0;
r->rtm_tos = rt->fl.fl4_tos;
r->rtm_table = RT_TABLE_MAIN;
+ RTA_PUT_U32(skb, RTA_TABLE, RT_TABLE_MAIN);
r->rtm_type = rt->rt_type;
r->rtm_scope = RT_SCOPE_UNIVERSE;
r->rtm_protocol = RTPROT_UNSPEC;
[FRA_PRIORITY] = { .type = NLA_U32 },
[FRA_SRC] = { .minlen = sizeof(struct in6_addr) },
[FRA_DST] = { .minlen = sizeof(struct in6_addr) },
+ [FRA_TABLE] = { .type = NLA_U32 },
};
static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
if (inet6_rtm_to_rtmsg(r, arg, &rtmsg))
return -EINVAL;
- return ip6_route_del(&rtmsg, nlh, arg, &NETLINK_CB(skb), r->rtm_table);
+ return ip6_route_del(&rtmsg, nlh, arg, &NETLINK_CB(skb),
+ rtm_get_table(arg, r->rtm_table));
}
int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
if (inet6_rtm_to_rtmsg(r, arg, &rtmsg))
return -EINVAL;
- return ip6_route_add(&rtmsg, nlh, arg, &NETLINK_CB(skb), r->rtm_table);
+ return ip6_route_add(&rtmsg, nlh, arg, &NETLINK_CB(skb),
+ rtm_get_table(arg, r->rtm_table));
}
struct rt6_rtnl_dump_arg
struct nlmsghdr *nlh;
unsigned char *b = skb->tail;
struct rta_cacheinfo ci;
+ u32 table;
if (prefix) { /* user wants prefix routes only */
if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
rtm->rtm_src_len = rt->rt6i_src.plen;
rtm->rtm_tos = 0;
if (rt->rt6i_table)
- rtm->rtm_table = rt->rt6i_table->tb6_id;
+ table = rt->rt6i_table->tb6_id;
else
- rtm->rtm_table = RT6_TABLE_UNSPEC;
+ table = RT6_TABLE_UNSPEC;
+ rtm->rtm_table = table;
+ RTA_PUT_U32(skb, RTA_TABLE, table);
if (rt->rt6i_flags&RTF_REJECT)
rtm->rtm_type = RTN_UNREACHABLE;
else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK))