forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
472 lines
12 KiB
472 lines
12 KiB
#ifndef __LINUX_MROUTE_BASE_H |
|
#define __LINUX_MROUTE_BASE_H |
|
|
|
#include <linux/netdevice.h> |
|
#include <linux/rhashtable-types.h> |
|
#include <linux/spinlock.h> |
|
#include <net/net_namespace.h> |
|
#include <net/sock.h> |
|
#include <net/fib_notifier.h> |
|
#include <net/ip_fib.h> |
|
|
|
/** |
|
* struct vif_device - interface representor for multicast routing |
|
* @dev: network device being used |
|
* @bytes_in: statistic; bytes ingressing |
|
* @bytes_out: statistic; bytes egresing |
|
* @pkt_in: statistic; packets ingressing |
|
* @pkt_out: statistic; packets egressing |
|
* @rate_limit: Traffic shaping (NI) |
|
* @threshold: TTL threshold |
|
* @flags: Control flags |
|
* @link: Physical interface index |
|
* @dev_parent_id: device parent id |
|
* @local: Local address |
|
* @remote: Remote address for tunnels |
|
*/ |
|
struct vif_device { |
|
struct net_device *dev; |
|
unsigned long bytes_in, bytes_out; |
|
unsigned long pkt_in, pkt_out; |
|
unsigned long rate_limit; |
|
unsigned char threshold; |
|
unsigned short flags; |
|
int link; |
|
|
|
/* Currently only used by ipmr */ |
|
struct netdev_phys_item_id dev_parent_id; |
|
__be32 local, remote; |
|
}; |
|
|
|
struct vif_entry_notifier_info { |
|
struct fib_notifier_info info; |
|
struct net_device *dev; |
|
unsigned short vif_index; |
|
unsigned short vif_flags; |
|
u32 tb_id; |
|
}; |
|
|
|
static inline int mr_call_vif_notifier(struct notifier_block *nb, |
|
unsigned short family, |
|
enum fib_event_type event_type, |
|
struct vif_device *vif, |
|
unsigned short vif_index, u32 tb_id, |
|
struct netlink_ext_ack *extack) |
|
{ |
|
struct vif_entry_notifier_info info = { |
|
.info = { |
|
.family = family, |
|
.extack = extack, |
|
}, |
|
.dev = vif->dev, |
|
.vif_index = vif_index, |
|
.vif_flags = vif->flags, |
|
.tb_id = tb_id, |
|
}; |
|
|
|
return call_fib_notifier(nb, event_type, &info.info); |
|
} |
|
|
|
static inline int mr_call_vif_notifiers(struct net *net, |
|
unsigned short family, |
|
enum fib_event_type event_type, |
|
struct vif_device *vif, |
|
unsigned short vif_index, u32 tb_id, |
|
unsigned int *ipmr_seq) |
|
{ |
|
struct vif_entry_notifier_info info = { |
|
.info = { |
|
.family = family, |
|
}, |
|
.dev = vif->dev, |
|
.vif_index = vif_index, |
|
.vif_flags = vif->flags, |
|
.tb_id = tb_id, |
|
}; |
|
|
|
ASSERT_RTNL(); |
|
(*ipmr_seq)++; |
|
return call_fib_notifiers(net, event_type, &info.info); |
|
} |
|
|
|
#ifndef MAXVIFS |
|
/* This one is nasty; value is defined in uapi using different symbols for |
|
* mroute and morute6 but both map into same 32. |
|
*/ |
|
#define MAXVIFS 32 |
|
#endif |
|
|
|
#define VIF_EXISTS(_mrt, _idx) (!!((_mrt)->vif_table[_idx].dev)) |
|
|
|
/* mfc_flags: |
|
* MFC_STATIC - the entry was added statically (not by a routing daemon) |
|
* MFC_OFFLOAD - the entry was offloaded to the hardware |
|
*/ |
|
enum { |
|
MFC_STATIC = BIT(0), |
|
MFC_OFFLOAD = BIT(1), |
|
}; |
|
|
|
/** |
|
* struct mr_mfc - common multicast routing entries |
|
* @mnode: rhashtable list |
|
* @mfc_parent: source interface (iif) |
|
* @mfc_flags: entry flags |
|
* @expires: unresolved entry expire time |
|
* @unresolved: unresolved cached skbs |
|
* @last_assert: time of last assert |
|
* @minvif: minimum VIF id |
|
* @maxvif: maximum VIF id |
|
* @bytes: bytes that have passed for this entry |
|
* @pkt: packets that have passed for this entry |
|
* @wrong_if: number of wrong source interface hits |
|
* @lastuse: time of last use of the group (traffic or update) |
|
* @ttls: OIF TTL threshold array |
|
* @refcount: reference count for this entry |
|
* @list: global entry list |
|
* @rcu: used for entry destruction |
|
* @free: Operation used for freeing an entry under RCU |
|
*/ |
|
struct mr_mfc { |
|
struct rhlist_head mnode; |
|
unsigned short mfc_parent; |
|
int mfc_flags; |
|
|
|
union { |
|
struct { |
|
unsigned long expires; |
|
struct sk_buff_head unresolved; |
|
} unres; |
|
struct { |
|
unsigned long last_assert; |
|
int minvif; |
|
int maxvif; |
|
unsigned long bytes; |
|
unsigned long pkt; |
|
unsigned long wrong_if; |
|
unsigned long lastuse; |
|
unsigned char ttls[MAXVIFS]; |
|
refcount_t refcount; |
|
} res; |
|
} mfc_un; |
|
struct list_head list; |
|
struct rcu_head rcu; |
|
void (*free)(struct rcu_head *head); |
|
}; |
|
|
|
static inline void mr_cache_put(struct mr_mfc *c) |
|
{ |
|
if (refcount_dec_and_test(&c->mfc_un.res.refcount)) |
|
call_rcu(&c->rcu, c->free); |
|
} |
|
|
|
static inline void mr_cache_hold(struct mr_mfc *c) |
|
{ |
|
refcount_inc(&c->mfc_un.res.refcount); |
|
} |
|
|
|
struct mfc_entry_notifier_info { |
|
struct fib_notifier_info info; |
|
struct mr_mfc *mfc; |
|
u32 tb_id; |
|
}; |
|
|
|
static inline int mr_call_mfc_notifier(struct notifier_block *nb, |
|
unsigned short family, |
|
enum fib_event_type event_type, |
|
struct mr_mfc *mfc, u32 tb_id, |
|
struct netlink_ext_ack *extack) |
|
{ |
|
struct mfc_entry_notifier_info info = { |
|
.info = { |
|
.family = family, |
|
.extack = extack, |
|
}, |
|
.mfc = mfc, |
|
.tb_id = tb_id |
|
}; |
|
|
|
return call_fib_notifier(nb, event_type, &info.info); |
|
} |
|
|
|
static inline int mr_call_mfc_notifiers(struct net *net, |
|
unsigned short family, |
|
enum fib_event_type event_type, |
|
struct mr_mfc *mfc, u32 tb_id, |
|
unsigned int *ipmr_seq) |
|
{ |
|
struct mfc_entry_notifier_info info = { |
|
.info = { |
|
.family = family, |
|
}, |
|
.mfc = mfc, |
|
.tb_id = tb_id |
|
}; |
|
|
|
ASSERT_RTNL(); |
|
(*ipmr_seq)++; |
|
return call_fib_notifiers(net, event_type, &info.info); |
|
} |
|
|
|
struct mr_table; |
|
|
|
/** |
|
* struct mr_table_ops - callbacks and info for protocol-specific ops |
|
* @rht_params: parameters for accessing the MFC hash |
|
* @cmparg_any: a hash key to be used for matching on (*,*) routes |
|
*/ |
|
struct mr_table_ops { |
|
const struct rhashtable_params *rht_params; |
|
void *cmparg_any; |
|
}; |
|
|
|
/** |
|
* struct mr_table - a multicast routing table |
|
* @list: entry within a list of multicast routing tables |
|
* @net: net where this table belongs |
|
* @ops: protocol specific operations |
|
* @id: identifier of the table |
|
* @mroute_sk: socket associated with the table |
|
* @ipmr_expire_timer: timer for handling unresolved routes |
|
* @mfc_unres_queue: list of unresolved MFC entries |
|
* @vif_table: array containing all possible vifs |
|
* @mfc_hash: Hash table of all resolved routes for easy lookup |
|
* @mfc_cache_list: list of resovled routes for possible traversal |
|
* @maxvif: Identifier of highest value vif currently in use |
|
* @cache_resolve_queue_len: current size of unresolved queue |
|
* @mroute_do_assert: Whether to inform userspace on wrong ingress |
|
* @mroute_do_pim: Whether to receive IGMP PIMv1 |
|
* @mroute_reg_vif_num: PIM-device vif index |
|
*/ |
|
struct mr_table { |
|
struct list_head list; |
|
possible_net_t net; |
|
struct mr_table_ops ops; |
|
u32 id; |
|
struct sock __rcu *mroute_sk; |
|
struct timer_list ipmr_expire_timer; |
|
struct list_head mfc_unres_queue; |
|
struct vif_device vif_table[MAXVIFS]; |
|
struct rhltable mfc_hash; |
|
struct list_head mfc_cache_list; |
|
int maxvif; |
|
atomic_t cache_resolve_queue_len; |
|
bool mroute_do_assert; |
|
bool mroute_do_pim; |
|
bool mroute_do_wrvifwhole; |
|
int mroute_reg_vif_num; |
|
}; |
|
|
|
#ifdef CONFIG_IP_MROUTE_COMMON |
|
void vif_device_init(struct vif_device *v, |
|
struct net_device *dev, |
|
unsigned long rate_limit, |
|
unsigned char threshold, |
|
unsigned short flags, |
|
unsigned short get_iflink_mask); |
|
|
|
struct mr_table * |
|
mr_table_alloc(struct net *net, u32 id, |
|
struct mr_table_ops *ops, |
|
void (*expire_func)(struct timer_list *t), |
|
void (*table_set)(struct mr_table *mrt, |
|
struct net *net)); |
|
|
|
/* These actually return 'struct mr_mfc *', but to avoid need for explicit |
|
* castings they simply return void. |
|
*/ |
|
void *mr_mfc_find_parent(struct mr_table *mrt, |
|
void *hasharg, int parent); |
|
void *mr_mfc_find_any_parent(struct mr_table *mrt, int vifi); |
|
void *mr_mfc_find_any(struct mr_table *mrt, int vifi, void *hasharg); |
|
|
|
int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, |
|
struct mr_mfc *c, struct rtmsg *rtm); |
|
int mr_table_dump(struct mr_table *mrt, struct sk_buff *skb, |
|
struct netlink_callback *cb, |
|
int (*fill)(struct mr_table *mrt, struct sk_buff *skb, |
|
u32 portid, u32 seq, struct mr_mfc *c, |
|
int cmd, int flags), |
|
spinlock_t *lock, struct fib_dump_filter *filter); |
|
int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb, |
|
struct mr_table *(*iter)(struct net *net, |
|
struct mr_table *mrt), |
|
int (*fill)(struct mr_table *mrt, |
|
struct sk_buff *skb, |
|
u32 portid, u32 seq, struct mr_mfc *c, |
|
int cmd, int flags), |
|
spinlock_t *lock, struct fib_dump_filter *filter); |
|
|
|
int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family, |
|
int (*rules_dump)(struct net *net, |
|
struct notifier_block *nb, |
|
struct netlink_ext_ack *extack), |
|
struct mr_table *(*mr_iter)(struct net *net, |
|
struct mr_table *mrt), |
|
rwlock_t *mrt_lock, struct netlink_ext_ack *extack); |
|
#else |
|
static inline void vif_device_init(struct vif_device *v, |
|
struct net_device *dev, |
|
unsigned long rate_limit, |
|
unsigned char threshold, |
|
unsigned short flags, |
|
unsigned short get_iflink_mask) |
|
{ |
|
} |
|
|
|
static inline void *mr_mfc_find_parent(struct mr_table *mrt, |
|
void *hasharg, int parent) |
|
{ |
|
return NULL; |
|
} |
|
|
|
static inline void *mr_mfc_find_any_parent(struct mr_table *mrt, |
|
int vifi) |
|
{ |
|
return NULL; |
|
} |
|
|
|
static inline struct mr_mfc *mr_mfc_find_any(struct mr_table *mrt, |
|
int vifi, void *hasharg) |
|
{ |
|
return NULL; |
|
} |
|
|
|
static inline int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, |
|
struct mr_mfc *c, struct rtmsg *rtm) |
|
{ |
|
return -EINVAL; |
|
} |
|
|
|
static inline int |
|
mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb, |
|
struct mr_table *(*iter)(struct net *net, |
|
struct mr_table *mrt), |
|
int (*fill)(struct mr_table *mrt, |
|
struct sk_buff *skb, |
|
u32 portid, u32 seq, struct mr_mfc *c, |
|
int cmd, int flags), |
|
spinlock_t *lock, struct fib_dump_filter *filter) |
|
{ |
|
return -EINVAL; |
|
} |
|
|
|
static inline int mr_dump(struct net *net, struct notifier_block *nb, |
|
unsigned short family, |
|
int (*rules_dump)(struct net *net, |
|
struct notifier_block *nb, |
|
struct netlink_ext_ack *extack), |
|
struct mr_table *(*mr_iter)(struct net *net, |
|
struct mr_table *mrt), |
|
rwlock_t *mrt_lock, struct netlink_ext_ack *extack) |
|
{ |
|
return -EINVAL; |
|
} |
|
#endif |
|
|
|
static inline void *mr_mfc_find(struct mr_table *mrt, void *hasharg) |
|
{ |
|
return mr_mfc_find_parent(mrt, hasharg, -1); |
|
} |
|
|
|
#ifdef CONFIG_PROC_FS |
|
struct mr_vif_iter { |
|
struct seq_net_private p; |
|
struct mr_table *mrt; |
|
int ct; |
|
}; |
|
|
|
struct mr_mfc_iter { |
|
struct seq_net_private p; |
|
struct mr_table *mrt; |
|
struct list_head *cache; |
|
|
|
/* Lock protecting the mr_table's unresolved queue */ |
|
spinlock_t *lock; |
|
}; |
|
|
|
#ifdef CONFIG_IP_MROUTE_COMMON |
|
void *mr_vif_seq_idx(struct net *net, struct mr_vif_iter *iter, loff_t pos); |
|
void *mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos); |
|
|
|
static inline void *mr_vif_seq_start(struct seq_file *seq, loff_t *pos) |
|
{ |
|
return *pos ? mr_vif_seq_idx(seq_file_net(seq), |
|
seq->private, *pos - 1) |
|
: SEQ_START_TOKEN; |
|
} |
|
|
|
/* These actually return 'struct mr_mfc *', but to avoid need for explicit |
|
* castings they simply return void. |
|
*/ |
|
void *mr_mfc_seq_idx(struct net *net, |
|
struct mr_mfc_iter *it, loff_t pos); |
|
void *mr_mfc_seq_next(struct seq_file *seq, void *v, |
|
loff_t *pos); |
|
|
|
static inline void *mr_mfc_seq_start(struct seq_file *seq, loff_t *pos, |
|
struct mr_table *mrt, spinlock_t *lock) |
|
{ |
|
struct mr_mfc_iter *it = seq->private; |
|
|
|
it->mrt = mrt; |
|
it->cache = NULL; |
|
it->lock = lock; |
|
|
|
return *pos ? mr_mfc_seq_idx(seq_file_net(seq), |
|
seq->private, *pos - 1) |
|
: SEQ_START_TOKEN; |
|
} |
|
|
|
static inline void mr_mfc_seq_stop(struct seq_file *seq, void *v) |
|
{ |
|
struct mr_mfc_iter *it = seq->private; |
|
struct mr_table *mrt = it->mrt; |
|
|
|
if (it->cache == &mrt->mfc_unres_queue) |
|
spin_unlock_bh(it->lock); |
|
else if (it->cache == &mrt->mfc_cache_list) |
|
rcu_read_unlock(); |
|
} |
|
#else |
|
static inline void *mr_vif_seq_idx(struct net *net, struct mr_vif_iter *iter, |
|
loff_t pos) |
|
{ |
|
return NULL; |
|
} |
|
|
|
static inline void *mr_vif_seq_next(struct seq_file *seq, |
|
void *v, loff_t *pos) |
|
{ |
|
return NULL; |
|
} |
|
|
|
static inline void *mr_vif_seq_start(struct seq_file *seq, loff_t *pos) |
|
{ |
|
return NULL; |
|
} |
|
|
|
static inline void *mr_mfc_seq_idx(struct net *net, |
|
struct mr_mfc_iter *it, loff_t pos) |
|
{ |
|
return NULL; |
|
} |
|
|
|
static inline void *mr_mfc_seq_next(struct seq_file *seq, void *v, |
|
loff_t *pos) |
|
{ |
|
return NULL; |
|
} |
|
|
|
static inline void *mr_mfc_seq_start(struct seq_file *seq, loff_t *pos, |
|
struct mr_table *mrt, spinlock_t *lock) |
|
{ |
|
return NULL; |
|
} |
|
|
|
static inline void mr_mfc_seq_stop(struct seq_file *seq, void *v) |
|
{ |
|
} |
|
#endif |
|
#endif |
|
#endif
|
|
|