Skip to content

Commit 088aa3e

Browse files
Yuval Mintzdavem330
authored andcommitted
ip6mr: Support fib notifications
In similar fashion to ipmr, support fib notifications for ip6mr mfc and vif related events. This would later allow drivers to react to said notifications and offload the IPv6 mroutes. Signed-off-by: Yuval Mintz <[email protected]> Signed-off-by: Ido Schimmel <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent cdc9f94 commit 088aa3e

File tree

2 files changed

+106
-8
lines changed

2 files changed

+106
-8
lines changed

include/net/netns/ipv6.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ struct netns_ipv6 {
9696
atomic_t fib6_sernum;
9797
struct seg6_pernet_data *seg6_data;
9898
struct fib_notifier_ops *notifier_ops;
99+
struct fib_notifier_ops *ip6mr_notifier_ops;
100+
unsigned int ipmr_seq; /* protected by rtnl_mutex */
99101
struct {
100102
struct hlist_head head;
101103
spinlock_t lock;

net/ipv6/ip6mr.c

Lines changed: 104 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,16 @@ static void __net_exit ip6mr_rules_exit(struct net *net)
258258
fib_rules_unregister(net->ipv6.mr6_rules_ops);
259259
rtnl_unlock();
260260
}
261+
262+
static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb)
263+
{
264+
return fib_rules_dump(net, nb, RTNL_FAMILY_IP6MR);
265+
}
266+
267+
static unsigned int ip6mr_rules_seq_read(struct net *net)
268+
{
269+
return fib_rules_seq_read(net, RTNL_FAMILY_IP6MR);
270+
}
261271
#else
262272
#define ip6mr_for_each_table(mrt, net) \
263273
for (mrt = net->ipv6.mrt6; mrt; mrt = NULL)
@@ -295,6 +305,16 @@ static void __net_exit ip6mr_rules_exit(struct net *net)
295305
net->ipv6.mrt6 = NULL;
296306
rtnl_unlock();
297307
}
308+
309+
static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb)
310+
{
311+
return 0;
312+
}
313+
314+
static unsigned int ip6mr_rules_seq_read(struct net *net)
315+
{
316+
return 0;
317+
}
298318
#endif
299319

300320
static int ip6mr_hash_cmp(struct rhashtable_compare_arg *arg,
@@ -653,10 +673,25 @@ static struct net_device *ip6mr_reg_vif(struct net *net, struct mr_table *mrt)
653673
}
654674
#endif
655675

656-
/*
657-
* Delete a VIF entry
658-
*/
676+
static int call_ip6mr_vif_entry_notifiers(struct net *net,
677+
enum fib_event_type event_type,
678+
struct vif_device *vif,
679+
mifi_t vif_index, u32 tb_id)
680+
{
681+
return mr_call_vif_notifiers(net, RTNL_FAMILY_IP6MR, event_type,
682+
vif, vif_index, tb_id,
683+
&net->ipv6.ipmr_seq);
684+
}
659685

686+
static int call_ip6mr_mfc_entry_notifiers(struct net *net,
687+
enum fib_event_type event_type,
688+
struct mfc6_cache *mfc, u32 tb_id)
689+
{
690+
return mr_call_mfc_notifiers(net, RTNL_FAMILY_IP6MR, event_type,
691+
&mfc->_c, tb_id, &net->ipv6.ipmr_seq);
692+
}
693+
694+
/* Delete a VIF entry */
660695
static int mif6_delete(struct mr_table *mrt, int vifi, int notify,
661696
struct list_head *head)
662697
{
@@ -669,6 +704,11 @@ static int mif6_delete(struct mr_table *mrt, int vifi, int notify,
669704

670705
v = &mrt->vif_table[vifi];
671706

707+
if (VIF_EXISTS(mrt, vifi))
708+
call_ip6mr_vif_entry_notifiers(read_pnet(&mrt->net),
709+
FIB_EVENT_VIF_DEL, v, vifi,
710+
mrt->id);
711+
672712
write_lock_bh(&mrt_lock);
673713
dev = v->dev;
674714
v->dev = NULL;
@@ -887,6 +927,8 @@ static int mif6_add(struct net *net, struct mr_table *mrt,
887927
if (vifi + 1 > mrt->maxvif)
888928
mrt->maxvif = vifi + 1;
889929
write_unlock_bh(&mrt_lock);
930+
call_ip6mr_vif_entry_notifiers(net, FIB_EVENT_VIF_ADD,
931+
v, vifi, mrt->id);
890932
return 0;
891933
}
892934

@@ -1175,6 +1217,8 @@ static int ip6mr_mfc_delete(struct mr_table *mrt, struct mf6cctl *mfc,
11751217
rhltable_remove(&mrt->mfc_hash, &c->_c.mnode, ip6mr_rht_params);
11761218
list_del_rcu(&c->_c.list);
11771219

1220+
call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net),
1221+
FIB_EVENT_ENTRY_DEL, c, mrt->id);
11781222
mr6_netlink_event(mrt, c, RTM_DELROUTE);
11791223
ip6mr_cache_free(c);
11801224
return 0;
@@ -1203,21 +1247,63 @@ static int ip6mr_device_event(struct notifier_block *this,
12031247
return NOTIFY_DONE;
12041248
}
12051249

1250+
static unsigned int ip6mr_seq_read(struct net *net)
1251+
{
1252+
ASSERT_RTNL();
1253+
1254+
return net->ipv6.ipmr_seq + ip6mr_rules_seq_read(net);
1255+
}
1256+
1257+
static int ip6mr_dump(struct net *net, struct notifier_block *nb)
1258+
{
1259+
return mr_dump(net, nb, RTNL_FAMILY_IP6MR, ip6mr_rules_dump,
1260+
ip6mr_mr_table_iter, &mrt_lock);
1261+
}
1262+
12061263
static struct notifier_block ip6_mr_notifier = {
12071264
.notifier_call = ip6mr_device_event
12081265
};
12091266

1210-
/*
1211-
* Setup for IP multicast routing
1212-
*/
1267+
static const struct fib_notifier_ops ip6mr_notifier_ops_template = {
1268+
.family = RTNL_FAMILY_IP6MR,
1269+
.fib_seq_read = ip6mr_seq_read,
1270+
.fib_dump = ip6mr_dump,
1271+
.owner = THIS_MODULE,
1272+
};
1273+
1274+
static int __net_init ip6mr_notifier_init(struct net *net)
1275+
{
1276+
struct fib_notifier_ops *ops;
1277+
1278+
net->ipv6.ipmr_seq = 0;
12131279

1280+
ops = fib_notifier_ops_register(&ip6mr_notifier_ops_template, net);
1281+
if (IS_ERR(ops))
1282+
return PTR_ERR(ops);
1283+
1284+
net->ipv6.ip6mr_notifier_ops = ops;
1285+
1286+
return 0;
1287+
}
1288+
1289+
static void __net_exit ip6mr_notifier_exit(struct net *net)
1290+
{
1291+
fib_notifier_ops_unregister(net->ipv6.ip6mr_notifier_ops);
1292+
net->ipv6.ip6mr_notifier_ops = NULL;
1293+
}
1294+
1295+
/* Setup for IP multicast routing */
12141296
static int __net_init ip6mr_net_init(struct net *net)
12151297
{
12161298
int err;
12171299

1300+
err = ip6mr_notifier_init(net);
1301+
if (err)
1302+
return err;
1303+
12181304
err = ip6mr_rules_init(net);
12191305
if (err < 0)
1220-
goto fail;
1306+
goto ip6mr_rules_fail;
12211307

12221308
#ifdef CONFIG_PROC_FS
12231309
err = -ENOMEM;
@@ -1235,7 +1321,8 @@ static int __net_init ip6mr_net_init(struct net *net)
12351321
proc_vif_fail:
12361322
ip6mr_rules_exit(net);
12371323
#endif
1238-
fail:
1324+
ip6mr_rules_fail:
1325+
ip6mr_notifier_exit(net);
12391326
return err;
12401327
}
12411328

@@ -1246,6 +1333,7 @@ static void __net_exit ip6mr_net_exit(struct net *net)
12461333
remove_proc_entry("ip6_mr_vif", net->proc_net);
12471334
#endif
12481335
ip6mr_rules_exit(net);
1336+
ip6mr_notifier_exit(net);
12491337
}
12501338

12511339
static struct pernet_operations ip6mr_net_ops = {
@@ -1337,6 +1425,8 @@ static int ip6mr_mfc_add(struct net *net, struct mr_table *mrt,
13371425
if (!mrtsock)
13381426
c->_c.mfc_flags |= MFC_STATIC;
13391427
write_unlock_bh(&mrt_lock);
1428+
call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE,
1429+
c, mrt->id);
13401430
mr6_netlink_event(mrt, c, RTM_NEWROUTE);
13411431
return 0;
13421432
}
@@ -1388,6 +1478,8 @@ static int ip6mr_mfc_add(struct net *net, struct mr_table *mrt,
13881478
ip6mr_cache_resolve(net, mrt, uc, c);
13891479
ip6mr_cache_free(uc);
13901480
}
1481+
call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_ADD,
1482+
c, mrt->id);
13911483
mr6_netlink_event(mrt, c, RTM_NEWROUTE);
13921484
return 0;
13931485
}
@@ -1424,6 +1516,10 @@ static void mroute_clean_tables(struct mr_table *mrt, bool all)
14241516
spin_lock_bh(&mfc_unres_lock);
14251517
list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) {
14261518
list_del(&c->list);
1519+
call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net),
1520+
FIB_EVENT_ENTRY_DEL,
1521+
(struct mfc6_cache *)c,
1522+
mrt->id);
14271523
mr6_netlink_event(mrt, (struct mfc6_cache *)c,
14281524
RTM_DELROUTE);
14291525
ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c);

0 commit comments

Comments
 (0)