📄 em_meta.c
字号:
/* * net/sched/em_meta.c Metadata ematch * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Authors: Thomas Graf <tgraf@suug.ch> * * ========================================================================== * * The metadata ematch compares two meta objects where each object * represents either a meta value stored in the kernel or a static * value provided by userspace. The objects are not provided by * userspace itself but rather a definition providing the information * to build them. Every object is of a certain type which must be * equal to the object it is being compared to. * * The definition of a objects conists of the type (meta type), a * identifier (meta id) and additional type specific information. * The meta id is either TCF_META_TYPE_VALUE for values provided by * userspace or a index to the meta operations table consisting of * function pointers to type specific meta data collectors returning * the value of the requested meta value. * * lvalue rvalue * +-----------+ +-----------+ * | type: INT | | type: INT | * def | id: DEV | | id: VALUE | * | data: | | data: 3 | * +-----------+ +-----------+ * | | * ---> meta_ops[INT][DEV](...) | * | | * ----------- | * V V * +-----------+ +-----------+ * | type: INT | | type: INT | * obj | id: DEV | | id: VALUE | * | data: 2 |<--data got filled out | data: 3 | * +-----------+ +-----------+ * | | * --------------> 2 equals 3 <-------------- * * This is a simplified schema, the complexity varies depending * on the meta type. Obviously, the length of the data must also * be provided for non-numeric types. * * Additionaly, type dependant modifiers such as shift operators * or mask may be applied to extend the functionaliy. As of now, * the variable length type supports shifting the byte string to * the right, eating up any number of octets and thus supporting * wildcard interface name comparisons such as "ppp%" matching * ppp0..9. * * NOTE: Certain meta values depend on other subsystems and are * only available if that subsystem is enabled in the kernel. */#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/skbuff.h>#include <linux/random.h>#include <linux/tc_ematch/tc_em_meta.h>#include <net/dst.h>#include <net/route.h>#include <net/pkt_cls.h>#include <net/sock.h>struct meta_obj{ unsigned long value; unsigned int len;};struct meta_value{ struct tcf_meta_val hdr; unsigned long val; unsigned int len;};struct meta_match{ struct meta_value lvalue; struct meta_value rvalue;};static inline int meta_id(struct meta_value *v){ return TCF_META_ID(v->hdr.kind);}static inline int meta_type(struct meta_value *v){ return TCF_META_TYPE(v->hdr.kind);}#define META_COLLECTOR(FUNC) static void meta_##FUNC(struct sk_buff *skb, \ struct tcf_pkt_info *info, struct meta_value *v, \ struct meta_obj *dst, int *err)/************************************************************************** * System status & misc **************************************************************************/META_COLLECTOR(int_random){ get_random_bytes(&dst->value, sizeof(dst->value));}static inline unsigned long fixed_loadavg(int load){ int rnd_load = load + (FIXED_1/200); int rnd_frac = ((rnd_load & (FIXED_1-1)) * 100) >> FSHIFT; return ((rnd_load >> FSHIFT) * 100) + rnd_frac;}META_COLLECTOR(int_loadavg_0){ dst->value = fixed_loadavg(avenrun[0]);}META_COLLECTOR(int_loadavg_1){ dst->value = fixed_loadavg(avenrun[1]);}META_COLLECTOR(int_loadavg_2){ dst->value = fixed_loadavg(avenrun[2]);}/************************************************************************** * Device names & indices **************************************************************************/static inline int int_dev(struct net_device *dev, struct meta_obj *dst){ if (unlikely(dev == NULL)) return -1; dst->value = dev->ifindex; return 0;}static inline int var_dev(struct net_device *dev, struct meta_obj *dst){ if (unlikely(dev == NULL)) return -1; dst->value = (unsigned long) dev->name; dst->len = strlen(dev->name); return 0;}META_COLLECTOR(int_dev){ *err = int_dev(skb->dev, dst);}META_COLLECTOR(var_dev){ *err = var_dev(skb->dev, dst);}/************************************************************************** * skb attributes **************************************************************************/META_COLLECTOR(int_priority){ dst->value = skb->priority;}META_COLLECTOR(int_protocol){ /* Let userspace take care of the byte ordering */ dst->value = skb->protocol;}META_COLLECTOR(int_pkttype){ dst->value = skb->pkt_type;}META_COLLECTOR(int_pktlen){ dst->value = skb->len;}META_COLLECTOR(int_datalen){ dst->value = skb->data_len;}META_COLLECTOR(int_maclen){ dst->value = skb->mac_len;}/************************************************************************** * Netfilter **************************************************************************/META_COLLECTOR(int_mark){ dst->value = skb->mark;}/************************************************************************** * Traffic Control **************************************************************************/META_COLLECTOR(int_tcindex){ dst->value = skb->tc_index;}/************************************************************************** * Routing **************************************************************************/META_COLLECTOR(int_rtclassid){ if (unlikely(skb->dst == NULL)) *err = -1; else#ifdef CONFIG_NET_CLS_ROUTE dst->value = skb->dst->tclassid;#else dst->value = 0;#endif}META_COLLECTOR(int_rtiif){ if (unlikely(skb->dst == NULL)) *err = -1; else dst->value = ((struct rtable*) skb->dst)->fl.iif;}/************************************************************************** * Socket Attributes **************************************************************************/#define SKIP_NONLOCAL(skb) \ if (unlikely(skb->sk == NULL)) { \ *err = -1; \ return; \ }META_COLLECTOR(int_sk_family){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_family;}META_COLLECTOR(int_sk_state){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_state;}META_COLLECTOR(int_sk_reuse){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_reuse;}META_COLLECTOR(int_sk_bound_if){ SKIP_NONLOCAL(skb); /* No error if bound_dev_if is 0, legal userspace check */ dst->value = skb->sk->sk_bound_dev_if;}META_COLLECTOR(var_sk_bound_if){ SKIP_NONLOCAL(skb); if (skb->sk->sk_bound_dev_if == 0) { dst->value = (unsigned long) "any"; dst->len = 3; } else { struct net_device *dev; dev = dev_get_by_index(&init_net, skb->sk->sk_bound_dev_if); *err = var_dev(dev, dst); if (dev) dev_put(dev); }}META_COLLECTOR(int_sk_refcnt){ SKIP_NONLOCAL(skb); dst->value = atomic_read(&skb->sk->sk_refcnt);}META_COLLECTOR(int_sk_rcvbuf){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_rcvbuf;}META_COLLECTOR(int_sk_shutdown){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_shutdown;}META_COLLECTOR(int_sk_proto){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_protocol;}META_COLLECTOR(int_sk_type){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_type;}META_COLLECTOR(int_sk_rmem_alloc){ SKIP_NONLOCAL(skb); dst->value = atomic_read(&skb->sk->sk_rmem_alloc);}META_COLLECTOR(int_sk_wmem_alloc){ SKIP_NONLOCAL(skb); dst->value = atomic_read(&skb->sk->sk_wmem_alloc);}META_COLLECTOR(int_sk_omem_alloc){ SKIP_NONLOCAL(skb); dst->value = atomic_read(&skb->sk->sk_omem_alloc);}META_COLLECTOR(int_sk_rcv_qlen){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_receive_queue.qlen;}META_COLLECTOR(int_sk_snd_qlen){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_write_queue.qlen;}META_COLLECTOR(int_sk_wmem_queued){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_wmem_queued;}META_COLLECTOR(int_sk_fwd_alloc){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_forward_alloc;}META_COLLECTOR(int_sk_sndbuf){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_sndbuf;}META_COLLECTOR(int_sk_alloc){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_allocation;}META_COLLECTOR(int_sk_route_caps){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_route_caps;}META_COLLECTOR(int_sk_hash){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_hash;}META_COLLECTOR(int_sk_lingertime){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_lingertime / HZ;}META_COLLECTOR(int_sk_err_qlen){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_error_queue.qlen;}META_COLLECTOR(int_sk_ack_bl){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_ack_backlog;}META_COLLECTOR(int_sk_max_ack_bl){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_max_ack_backlog;}META_COLLECTOR(int_sk_prio){ SKIP_NONLOCAL(skb); dst->value = skb->sk->sk_priority;}META_COLLECTOR(int_sk_rcvlowat)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -