mirror of
https://github.com/torvalds/linux.git
synced 2024-12-05 02:23:16 +00:00
Merge branch 'net-Export-functions-for-nexthop-code'
David Ahern says: ==================== net: Export functions for nexthop code This set exports ipv4 and ipv6 fib functions for use by the nexthop code. It also adds new ones to send route notifications if a nexthop configuration changes. v2 - repost of patches dropped at the end of the last dev window added patch 8 which exports nh_update_mtu since it is inline with the other patches ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
e38f7cbd36
@ -452,6 +452,12 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
|
||||
struct netlink_ext_ack *extack);
|
||||
void fib6_nh_release(struct fib6_nh *fib6_nh);
|
||||
|
||||
int call_fib6_entry_notifiers(struct net *net,
|
||||
enum fib_event_type event_type,
|
||||
struct fib6_info *rt,
|
||||
struct netlink_ext_ack *extack);
|
||||
void fib6_rt_update(struct net *net, struct fib6_info *rt,
|
||||
struct nl_info *info);
|
||||
void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
|
||||
unsigned int flags);
|
||||
|
||||
@ -485,6 +491,7 @@ int fib6_tables_dump(struct net *net, struct notifier_block *nb);
|
||||
|
||||
void fib6_update_sernum(struct net *net, struct fib6_info *rt);
|
||||
void fib6_update_sernum_upto_root(struct net *net, struct fib6_info *rt);
|
||||
void fib6_update_sernum_stub(struct net *net, struct fib6_info *f6i);
|
||||
|
||||
void fib6_metric_set(struct fib6_info *f6i, int metric, u32 val);
|
||||
static inline bool fib6_metric_locked(struct fib6_info *f6i, int metric)
|
||||
|
@ -150,6 +150,7 @@ struct fib_info {
|
||||
#define fib_advmss fib_metrics->metrics[RTAX_ADVMSS-1]
|
||||
int fib_nhs;
|
||||
bool fib_nh_is_v6;
|
||||
bool nh_updated;
|
||||
struct rcu_head rcu;
|
||||
struct fib_nh fib_nh[0];
|
||||
#define fib_dev fib_nh[0].fib_nh_dev
|
||||
@ -200,7 +201,8 @@ static inline struct fib_nh_common *fib_info_nhc(struct fib_info *fi, int nhsel)
|
||||
#define FIB_TABLE_HASHSZ 2
|
||||
#endif
|
||||
|
||||
__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh);
|
||||
__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh,
|
||||
unsigned char scope);
|
||||
__be32 fib_result_prefsrc(struct net *net, struct fib_result *res);
|
||||
|
||||
#define FIB_RES_NHC(res) ((res).nhc)
|
||||
@ -231,6 +233,7 @@ int call_fib4_notifiers(struct net *net, enum fib_event_type event_type,
|
||||
int __net_init fib4_notifier_init(struct net *net);
|
||||
void __net_exit fib4_notifier_exit(struct net *net);
|
||||
|
||||
void fib_info_notify_update(struct net *net, struct nl_info *info);
|
||||
void fib_notify(struct net *net, struct notifier_block *nb);
|
||||
|
||||
struct fib_table {
|
||||
@ -429,11 +432,14 @@ int fib_sync_down_dev(struct net_device *dev, unsigned long event, bool force);
|
||||
int fib_sync_down_addr(struct net_device *dev, __be32 local);
|
||||
int fib_sync_up(struct net_device *dev, unsigned char nh_flags);
|
||||
void fib_sync_mtu(struct net_device *dev, u32 orig_mtu);
|
||||
void fib_nhc_update_mtu(struct fib_nh_common *nhc, u32 new, u32 orig);
|
||||
|
||||
#ifdef CONFIG_IP_ROUTE_MULTIPATH
|
||||
int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4,
|
||||
const struct sk_buff *skb, struct flow_keys *flkeys);
|
||||
#endif
|
||||
int fib_check_nh(struct net *net, struct fib_nh *nh, u32 table, u8 scope,
|
||||
struct netlink_ext_ack *extack);
|
||||
void fib_select_multipath(struct fib_result *res, int hash);
|
||||
void fib_select_path(struct net *net, struct fib_result *res,
|
||||
struct flowi4 *fl4, const struct sk_buff *skb);
|
||||
@ -469,6 +475,7 @@ static inline void fib_combine_itag(u32 *itag, const struct fib_result *res)
|
||||
#endif
|
||||
}
|
||||
|
||||
void fib_flush(struct net *net);
|
||||
void free_fib_info(struct fib_info *fi);
|
||||
|
||||
static inline void fib_info_hold(struct fib_info *fi)
|
||||
|
@ -45,6 +45,11 @@ struct ipv6_stub {
|
||||
struct fib6_config *cfg, gfp_t gfp_flags,
|
||||
struct netlink_ext_ack *extack);
|
||||
void (*fib6_nh_release)(struct fib6_nh *fib6_nh);
|
||||
void (*fib6_update_sernum)(struct net *net, struct fib6_info *rt);
|
||||
int (*ip6_del_rt)(struct net *net, struct fib6_info *rt);
|
||||
void (*fib6_rt_update)(struct net *net, struct fib6_info *rt,
|
||||
struct nl_info *info);
|
||||
|
||||
void (*udpv6_encap_enable)(void);
|
||||
void (*ndisc_send_na)(struct net_device *dev, const struct in6_addr *daddr,
|
||||
const struct in6_addr *solicited_addr,
|
||||
|
@ -192,7 +192,7 @@ int fib_unmerge(struct net *net)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fib_flush(struct net *net)
|
||||
void fib_flush(struct net *net)
|
||||
{
|
||||
int flushed = 0;
|
||||
unsigned int h;
|
||||
|
@ -1092,15 +1092,13 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
|
||||
struct netlink_ext_ack *extack)
|
||||
int fib_check_nh(struct net *net, struct fib_nh *nh, u32 table, u8 scope,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct net *net = cfg->fc_nlinfo.nl_net;
|
||||
u32 table = cfg->fc_table;
|
||||
int err;
|
||||
|
||||
if (nh->fib_nh_gw_family == AF_INET)
|
||||
err = fib_check_nh_v4_gw(net, nh, table, cfg->fc_scope, extack);
|
||||
err = fib_check_nh_v4_gw(net, nh, table, scope, extack);
|
||||
else if (nh->fib_nh_gw_family == AF_INET6)
|
||||
err = fib_check_nh_v6_gw(net, nh, table, extack);
|
||||
else
|
||||
@ -1191,11 +1189,10 @@ static void fib_info_hash_move(struct hlist_head *new_info_hash,
|
||||
fib_info_hash_free(old_laddrhash, bytes);
|
||||
}
|
||||
|
||||
__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh)
|
||||
__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh,
|
||||
unsigned char scope)
|
||||
{
|
||||
nh->nh_saddr = inet_select_addr(nh->fib_nh_dev,
|
||||
nh->fib_nh_gw4,
|
||||
nh->nh_parent->fib_scope);
|
||||
nh->nh_saddr = inet_select_addr(nh->fib_nh_dev, nh->fib_nh_gw4, scope);
|
||||
nh->nh_saddr_genid = atomic_read(&net->ipv4.dev_addr_genid);
|
||||
|
||||
return nh->nh_saddr;
|
||||
@ -1213,7 +1210,7 @@ __be32 fib_result_prefsrc(struct net *net, struct fib_result *res)
|
||||
if (nh->nh_saddr_genid == atomic_read(&net->ipv4.dev_addr_genid))
|
||||
return nh->nh_saddr;
|
||||
|
||||
return fib_info_update_nh_saddr(net, nh);
|
||||
return fib_info_update_nh_saddr(net, nh, res->fi->fib_scope);
|
||||
}
|
||||
|
||||
static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc)
|
||||
@ -1377,7 +1374,9 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
|
||||
int linkdown = 0;
|
||||
|
||||
change_nexthops(fi) {
|
||||
err = fib_check_nh(cfg, nexthop_nh, extack);
|
||||
err = fib_check_nh(cfg->fc_nlinfo.nl_net, nexthop_nh,
|
||||
cfg->fc_table, cfg->fc_scope,
|
||||
extack);
|
||||
if (err != 0)
|
||||
goto failure;
|
||||
if (nexthop_nh->fib_nh_flags & RTNH_F_LINKDOWN)
|
||||
@ -1393,7 +1392,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
|
||||
}
|
||||
|
||||
change_nexthops(fi) {
|
||||
fib_info_update_nh_saddr(net, nexthop_nh);
|
||||
fib_info_update_nh_saddr(net, nexthop_nh, fi->fib_scope);
|
||||
if (nexthop_nh->fib_nh_gw_family == AF_INET6)
|
||||
fi->fib_nh_is_v6 = true;
|
||||
} endfor_nexthops(fi)
|
||||
@ -1713,7 +1712,7 @@ static int call_fib_nh_notifiers(struct fib_nh *nh,
|
||||
* - if the new MTU is greater than the PMTU, don't make any change
|
||||
* - otherwise, unlock and set PMTU
|
||||
*/
|
||||
static void nh_update_mtu(struct fib_nh_common *nhc, u32 new, u32 orig)
|
||||
void fib_nhc_update_mtu(struct fib_nh_common *nhc, u32 new, u32 orig)
|
||||
{
|
||||
struct fnhe_hash_bucket *bucket;
|
||||
int i;
|
||||
@ -1749,7 +1748,7 @@ void fib_sync_mtu(struct net_device *dev, u32 orig_mtu)
|
||||
|
||||
hlist_for_each_entry(nh, head, nh_hash) {
|
||||
if (nh->fib_nh_dev == dev)
|
||||
nh_update_mtu(&nh->nh_common, dev->mtu, orig_mtu);
|
||||
fib_nhc_update_mtu(&nh->nh_common, dev->mtu, orig_mtu);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1943,6 +1943,78 @@ int fib_table_flush(struct net *net, struct fib_table *tb, bool flush_all)
|
||||
return found;
|
||||
}
|
||||
|
||||
/* derived from fib_trie_free */
|
||||
static void __fib_info_notify_update(struct net *net, struct fib_table *tb,
|
||||
struct nl_info *info)
|
||||
{
|
||||
struct trie *t = (struct trie *)tb->tb_data;
|
||||
struct key_vector *pn = t->kv;
|
||||
unsigned long cindex = 1;
|
||||
struct fib_alias *fa;
|
||||
|
||||
for (;;) {
|
||||
struct key_vector *n;
|
||||
|
||||
if (!(cindex--)) {
|
||||
t_key pkey = pn->key;
|
||||
|
||||
if (IS_TRIE(pn))
|
||||
break;
|
||||
|
||||
n = pn;
|
||||
pn = node_parent(pn);
|
||||
cindex = get_index(pkey, pn);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* grab the next available node */
|
||||
n = get_child(pn, cindex);
|
||||
if (!n)
|
||||
continue;
|
||||
|
||||
if (IS_TNODE(n)) {
|
||||
/* record pn and cindex for leaf walking */
|
||||
pn = n;
|
||||
cindex = 1ul << n->bits;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
hlist_for_each_entry(fa, &n->leaf, fa_list) {
|
||||
struct fib_info *fi = fa->fa_info;
|
||||
|
||||
if (!fi || !fi->nh_updated || fa->tb_id != tb->tb_id)
|
||||
continue;
|
||||
|
||||
rtmsg_fib(RTM_NEWROUTE, htonl(n->key), fa,
|
||||
KEYLENGTH - fa->fa_slen, tb->tb_id,
|
||||
info, NLM_F_REPLACE);
|
||||
|
||||
/* call_fib_entry_notifiers will be removed when
|
||||
* in-kernel notifier is implemented and supported
|
||||
* for nexthop objects
|
||||
*/
|
||||
call_fib_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE,
|
||||
n->key,
|
||||
KEYLENGTH - fa->fa_slen, fa,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fib_info_notify_update(struct net *net, struct nl_info *info)
|
||||
{
|
||||
unsigned int h;
|
||||
|
||||
for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
|
||||
struct hlist_head *head = &net->ipv4.fib_table_hash[h];
|
||||
struct fib_table *tb;
|
||||
|
||||
hlist_for_each_entry_rcu(tb, head, tb_hlist)
|
||||
__fib_info_notify_update(net, tb, info);
|
||||
}
|
||||
}
|
||||
|
||||
static void fib_leaf_notify(struct net *net, struct key_vector *l,
|
||||
struct fib_table *tb, struct notifier_block *nb)
|
||||
{
|
||||
|
@ -183,6 +183,11 @@ static int eafnosupport_fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
static int eafnosupport_ip6_del_rt(struct net *net, struct fib6_info *rt)
|
||||
{
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
const struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) {
|
||||
.ipv6_dst_lookup = eafnosupport_ipv6_dst_lookup,
|
||||
.ipv6_route_input = eafnosupport_ipv6_route_input,
|
||||
@ -192,6 +197,7 @@ const struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) {
|
||||
.fib6_select_path = eafnosupport_fib6_select_path,
|
||||
.ip6_mtu_from_fib6 = eafnosupport_ip6_mtu_from_fib6,
|
||||
.fib6_nh_init = eafnosupport_fib6_nh_init,
|
||||
.ip6_del_rt = eafnosupport_ip6_del_rt,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ipv6_stub);
|
||||
|
||||
|
@ -926,6 +926,9 @@ static const struct ipv6_stub ipv6_stub_impl = {
|
||||
.ip6_mtu_from_fib6 = ip6_mtu_from_fib6,
|
||||
.fib6_nh_init = fib6_nh_init,
|
||||
.fib6_nh_release = fib6_nh_release,
|
||||
.fib6_update_sernum = fib6_update_sernum_stub,
|
||||
.fib6_rt_update = fib6_rt_update,
|
||||
.ip6_del_rt = ip6_del_rt,
|
||||
.udpv6_encap_enable = udpv6_encap_enable,
|
||||
.ndisc_send_na = ndisc_send_na,
|
||||
.nd_tbl = &nd_tbl,
|
||||
|
@ -393,10 +393,10 @@ static int call_fib6_entry_notifier(struct notifier_block *nb, struct net *net,
|
||||
return call_fib6_notifier(nb, net, event_type, &info.info);
|
||||
}
|
||||
|
||||
static int call_fib6_entry_notifiers(struct net *net,
|
||||
enum fib_event_type event_type,
|
||||
struct fib6_info *rt,
|
||||
struct netlink_ext_ack *extack)
|
||||
int call_fib6_entry_notifiers(struct net *net,
|
||||
enum fib_event_type event_type,
|
||||
struct fib6_info *rt,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct fib6_entry_notifier_info info = {
|
||||
.info.extack = extack,
|
||||
@ -1222,6 +1222,14 @@ void fib6_update_sernum_upto_root(struct net *net, struct fib6_info *rt)
|
||||
__fib6_update_sernum_upto_root(rt, fib6_new_sernum(net));
|
||||
}
|
||||
|
||||
/* allow ipv4 to update sernum via ipv6_stub */
|
||||
void fib6_update_sernum_stub(struct net *net, struct fib6_info *f6i)
|
||||
{
|
||||
spin_lock_bh(&f6i->fib6_table->tb6_lock);
|
||||
fib6_update_sernum_upto_root(net, f6i);
|
||||
spin_unlock_bh(&f6i->fib6_table->tb6_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add routing information to the routing tree.
|
||||
* <destination addr>/<source addr>
|
||||
|
@ -5123,6 +5123,38 @@ errout:
|
||||
rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
|
||||
}
|
||||
|
||||
void fib6_rt_update(struct net *net, struct fib6_info *rt,
|
||||
struct nl_info *info)
|
||||
{
|
||||
u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
|
||||
struct sk_buff *skb;
|
||||
int err = -ENOBUFS;
|
||||
|
||||
/* call_fib6_entry_notifiers will be removed when in-kernel notifier
|
||||
* is implemented and supported for nexthop objects
|
||||
*/
|
||||
call_fib6_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE, rt, NULL);
|
||||
|
||||
skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
|
||||
if (!skb)
|
||||
goto errout;
|
||||
|
||||
err = rt6_fill_node(net, skb, rt, NULL, NULL, NULL, 0,
|
||||
RTM_NEWROUTE, info->portid, seq, NLM_F_REPLACE);
|
||||
if (err < 0) {
|
||||
/* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
|
||||
WARN_ON(err == -EMSGSIZE);
|
||||
kfree_skb(skb);
|
||||
goto errout;
|
||||
}
|
||||
rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
|
||||
info->nlh, gfp_any());
|
||||
return;
|
||||
errout:
|
||||
if (err < 0)
|
||||
rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
|
||||
}
|
||||
|
||||
static int ip6_route_dev_notify(struct notifier_block *this,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user