Blame view

net/sched/em_ipset.c 3.09 KB
6d4fa852a   Florian Westphal   net: sched: add i...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  /*
   * net/sched/em_ipset.c	ipset ematch
   *
   * Copyright (c) 2012 Florian Westphal <fw@strlen.de>
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * version 2 as published by the Free Software Foundation.
   */
  
  #include <linux/gfp.h>
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/string.h>
  #include <linux/skbuff.h>
  #include <linux/netfilter/xt_set.h>
  #include <linux/ipv6.h>
  #include <net/ip.h>
  #include <net/pkt_cls.h>
82a470f11   John Fastabend   net: sched: remov...
21
  static int em_ipset_change(struct net *net, void *data, int data_len,
6d4fa852a   Florian Westphal   net: sched: add i...
22
23
24
25
26
27
28
  			   struct tcf_ematch *em)
  {
  	struct xt_set_info *set = data;
  	ip_set_id_t index;
  
  	if (data_len != sizeof(*set))
  		return -EINVAL;
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
29
  	index = ip_set_nfnl_get_byindex(net, set->index);
6d4fa852a   Florian Westphal   net: sched: add i...
30
31
32
33
34
35
36
  	if (index == IPSET_INVALID_ID)
  		return -ENOENT;
  
  	em->datalen = sizeof(*set);
  	em->data = (unsigned long)kmemdup(data, em->datalen, GFP_KERNEL);
  	if (em->data)
  		return 0;
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
37
  	ip_set_nfnl_put(net, index);
6d4fa852a   Florian Westphal   net: sched: add i...
38
39
  	return -ENOMEM;
  }
82a470f11   John Fastabend   net: sched: remov...
40
  static void em_ipset_destroy(struct tcf_ematch *em)
6d4fa852a   Florian Westphal   net: sched: add i...
41
42
43
  {
  	const struct xt_set_info *set = (const void *) em->data;
  	if (set) {
82a470f11   John Fastabend   net: sched: remov...
44
  		ip_set_nfnl_put(em->net, set->index);
6d4fa852a   Florian Westphal   net: sched: add i...
45
46
47
48
49
50
51
52
53
54
55
  		kfree((void *) em->data);
  	}
  }
  
  static int em_ipset_match(struct sk_buff *skb, struct tcf_ematch *em,
  			  struct tcf_pkt_info *info)
  {
  	struct ip_set_adt_opt opt;
  	struct xt_action_param acpar;
  	const struct xt_set_info *set = (const void *) em->data;
  	struct net_device *dev, *indev = NULL;
613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
56
57
58
  	struct nf_hook_state state = {
  		.net	= em->net,
  	};
6d4fa852a   Florian Westphal   net: sched: add i...
59
  	int ret, network_offset;
d8b9605d2   Jiri Pirko   net: sched: fix s...
60
  	switch (tc_skb_protocol(skb)) {
6d4fa852a   Florian Westphal   net: sched: add i...
61
  	case htons(ETH_P_IP):
613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
62
  		state.pf = NFPROTO_IPV4;
6d4fa852a   Florian Westphal   net: sched: add i...
63
64
65
66
67
  		if (!pskb_network_may_pull(skb, sizeof(struct iphdr)))
  			return 0;
  		acpar.thoff = ip_hdrlen(skb);
  		break;
  	case htons(ETH_P_IPV6):
613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
68
  		state.pf = NFPROTO_IPV6;
6d4fa852a   Florian Westphal   net: sched: add i...
69
70
71
72
73
74
75
76
  		if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
  			return 0;
  		/* doesn't call ipv6_find_hdr() because ipset doesn't use thoff, yet */
  		acpar.thoff = sizeof(struct ipv6hdr);
  		break;
  	default:
  		return 0;
  	}
613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
77
  	opt.family = state.pf;
6d4fa852a   Florian Westphal   net: sched: add i...
78
79
80
  	opt.dim = set->dim;
  	opt.flags = set->flags;
  	opt.cmdflags = 0;
075e64c04   Jozsef Kadlecsik   netfilter: ipset:...
81
  	opt.ext.timeout = ~0u;
6d4fa852a   Florian Westphal   net: sched: add i...
82
83
84
85
86
87
88
  
  	network_offset = skb_network_offset(skb);
  	skb_pull(skb, network_offset);
  
  	dev = skb->dev;
  
  	rcu_read_lock();
17cebfd09   Eric W. Biederman   net: sched: Simpl...
89
90
  	if (skb->skb_iif)
  		indev = dev_get_by_index_rcu(em->net, skb->skb_iif);
6d4fa852a   Florian Westphal   net: sched: add i...
91

613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
92
93
94
  	state.in      = indev ? indev : dev;
  	state.out     = dev;
  	acpar.state   = &state;
6d4fa852a   Florian Westphal   net: sched: add i...
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
  
  	ret = ip_set_test(set->index, skb, &acpar, &opt);
  
  	rcu_read_unlock();
  
  	skb_push(skb, network_offset);
  	return ret;
  }
  
  static struct tcf_ematch_ops em_ipset_ops = {
  	.kind	  = TCF_EM_IPSET,
  	.change	  = em_ipset_change,
  	.destroy  = em_ipset_destroy,
  	.match	  = em_ipset_match,
  	.owner	  = THIS_MODULE,
  	.link	  = LIST_HEAD_INIT(em_ipset_ops.link)
  };
  
  static int __init init_em_ipset(void)
  {
  	return tcf_em_register(&em_ipset_ops);
  }
  
  static void __exit exit_em_ipset(void)
  {
  	tcf_em_unregister(&em_ipset_ops);
  }
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
  MODULE_DESCRIPTION("TC extended match for IP sets");
  
  module_init(init_em_ipset);
  module_exit(exit_em_ipset);
  
  MODULE_ALIAS_TCF_EMATCH(TCF_EM_IPSET);