Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <yuvalm@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Yuval Mintz and committed by
David S. Miller
088aa3ee cdc9f944

+106 -8
+2
include/net/netns/ipv6.h
··· 96 96 atomic_t fib6_sernum; 97 97 struct seg6_pernet_data *seg6_data; 98 98 struct fib_notifier_ops *notifier_ops; 99 + struct fib_notifier_ops *ip6mr_notifier_ops; 100 + unsigned int ipmr_seq; /* protected by rtnl_mutex */ 99 101 struct { 100 102 struct hlist_head head; 101 103 spinlock_t lock;
+104 -8
net/ipv6/ip6mr.c
··· 258 258 fib_rules_unregister(net->ipv6.mr6_rules_ops); 259 259 rtnl_unlock(); 260 260 } 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 + } 261 271 #else 262 272 #define ip6mr_for_each_table(mrt, net) \ 263 273 for (mrt = net->ipv6.mrt6; mrt; mrt = NULL) ··· 304 294 ip6mr_free_table(net->ipv6.mrt6); 305 295 net->ipv6.mrt6 = NULL; 306 296 rtnl_unlock(); 297 + } 298 + 299 + static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb) 300 + { 301 + return 0; 302 + } 303 + 304 + static unsigned int ip6mr_rules_seq_read(struct net *net) 305 + { 306 + return 0; 307 307 } 308 308 #endif 309 309 ··· 673 653 } 674 654 #endif 675 655 676 - /* 677 - * Delete a VIF entry 678 - */ 656 + static int call_ip6mr_vif_entry_notifiers(struct net *net, 657 + enum fib_event_type event_type, 658 + struct vif_device *vif, 659 + mifi_t vif_index, u32 tb_id) 660 + { 661 + return mr_call_vif_notifiers(net, RTNL_FAMILY_IP6MR, event_type, 662 + vif, vif_index, tb_id, 663 + &net->ipv6.ipmr_seq); 664 + } 679 665 666 + static int call_ip6mr_mfc_entry_notifiers(struct net *net, 667 + enum fib_event_type event_type, 668 + struct mfc6_cache *mfc, u32 tb_id) 669 + { 670 + return mr_call_mfc_notifiers(net, RTNL_FAMILY_IP6MR, event_type, 671 + &mfc->_c, tb_id, &net->ipv6.ipmr_seq); 672 + } 673 + 674 + /* Delete a VIF entry */ 680 675 static int mif6_delete(struct mr_table *mrt, int vifi, int notify, 681 676 struct list_head *head) 682 677 { ··· 703 668 return -EADDRNOTAVAIL; 704 669 705 670 v = &mrt->vif_table[vifi]; 671 + 672 + if (VIF_EXISTS(mrt, vifi)) 673 + call_ip6mr_vif_entry_notifiers(read_pnet(&mrt->net), 674 + FIB_EVENT_VIF_DEL, v, vifi, 675 + mrt->id); 706 676 707 677 write_lock_bh(&mrt_lock); 708 678 dev = v->dev; ··· 927 887 if (vifi + 1 > mrt->maxvif) 928 888 mrt->maxvif = vifi + 1; 929 889 write_unlock_bh(&mrt_lock); 890 + call_ip6mr_vif_entry_notifiers(net, FIB_EVENT_VIF_ADD, 891 + v, vifi, mrt->id); 930 892 return 0; 931 893 } 932 894 ··· 1217 1175 rhltable_remove(&mrt->mfc_hash, &c->_c.mnode, ip6mr_rht_params); 1218 1176 list_del_rcu(&c->_c.list); 1219 1177 1178 + call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net), 1179 + FIB_EVENT_ENTRY_DEL, c, mrt->id); 1220 1180 mr6_netlink_event(mrt, c, RTM_DELROUTE); 1221 1181 ip6mr_cache_free(c); 1222 1182 return 0; ··· 1247 1203 return NOTIFY_DONE; 1248 1204 } 1249 1205 1206 + static unsigned int ip6mr_seq_read(struct net *net) 1207 + { 1208 + ASSERT_RTNL(); 1209 + 1210 + return net->ipv6.ipmr_seq + ip6mr_rules_seq_read(net); 1211 + } 1212 + 1213 + static int ip6mr_dump(struct net *net, struct notifier_block *nb) 1214 + { 1215 + return mr_dump(net, nb, RTNL_FAMILY_IP6MR, ip6mr_rules_dump, 1216 + ip6mr_mr_table_iter, &mrt_lock); 1217 + } 1218 + 1250 1219 static struct notifier_block ip6_mr_notifier = { 1251 1220 .notifier_call = ip6mr_device_event 1252 1221 }; 1253 1222 1254 - /* 1255 - * Setup for IP multicast routing 1256 - */ 1223 + static const struct fib_notifier_ops ip6mr_notifier_ops_template = { 1224 + .family = RTNL_FAMILY_IP6MR, 1225 + .fib_seq_read = ip6mr_seq_read, 1226 + .fib_dump = ip6mr_dump, 1227 + .owner = THIS_MODULE, 1228 + }; 1257 1229 1230 + static int __net_init ip6mr_notifier_init(struct net *net) 1231 + { 1232 + struct fib_notifier_ops *ops; 1233 + 1234 + net->ipv6.ipmr_seq = 0; 1235 + 1236 + ops = fib_notifier_ops_register(&ip6mr_notifier_ops_template, net); 1237 + if (IS_ERR(ops)) 1238 + return PTR_ERR(ops); 1239 + 1240 + net->ipv6.ip6mr_notifier_ops = ops; 1241 + 1242 + return 0; 1243 + } 1244 + 1245 + static void __net_exit ip6mr_notifier_exit(struct net *net) 1246 + { 1247 + fib_notifier_ops_unregister(net->ipv6.ip6mr_notifier_ops); 1248 + net->ipv6.ip6mr_notifier_ops = NULL; 1249 + } 1250 + 1251 + /* Setup for IP multicast routing */ 1258 1252 static int __net_init ip6mr_net_init(struct net *net) 1259 1253 { 1260 1254 int err; 1261 1255 1256 + err = ip6mr_notifier_init(net); 1257 + if (err) 1258 + return err; 1259 + 1262 1260 err = ip6mr_rules_init(net); 1263 1261 if (err < 0) 1264 - goto fail; 1262 + goto ip6mr_rules_fail; 1265 1263 1266 1264 #ifdef CONFIG_PROC_FS 1267 1265 err = -ENOMEM; ··· 1321 1235 proc_vif_fail: 1322 1236 ip6mr_rules_exit(net); 1323 1237 #endif 1324 - fail: 1238 + ip6mr_rules_fail: 1239 + ip6mr_notifier_exit(net); 1325 1240 return err; 1326 1241 } 1327 1242 ··· 1333 1246 remove_proc_entry("ip6_mr_vif", net->proc_net); 1334 1247 #endif 1335 1248 ip6mr_rules_exit(net); 1249 + ip6mr_notifier_exit(net); 1336 1250 } 1337 1251 1338 1252 static struct pernet_operations ip6mr_net_ops = { ··· 1425 1337 if (!mrtsock) 1426 1338 c->_c.mfc_flags |= MFC_STATIC; 1427 1339 write_unlock_bh(&mrt_lock); 1340 + call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE, 1341 + c, mrt->id); 1428 1342 mr6_netlink_event(mrt, c, RTM_NEWROUTE); 1429 1343 return 0; 1430 1344 } ··· 1478 1388 ip6mr_cache_resolve(net, mrt, uc, c); 1479 1389 ip6mr_cache_free(uc); 1480 1390 } 1391 + call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_ADD, 1392 + c, mrt->id); 1481 1393 mr6_netlink_event(mrt, c, RTM_NEWROUTE); 1482 1394 return 0; 1483 1395 } ··· 1516 1424 spin_lock_bh(&mfc_unres_lock); 1517 1425 list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { 1518 1426 list_del(&c->list); 1427 + call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net), 1428 + FIB_EVENT_ENTRY_DEL, 1429 + (struct mfc6_cache *)c, 1430 + mrt->id); 1519 1431 mr6_netlink_event(mrt, (struct mfc6_cache *)c, 1520 1432 RTM_DELROUTE); 1521 1433 ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c);