MoonGen
 All Files Functions Variables Pages
filter.lua
Go to the documentation of this file.
1 ---------------------------------
2 --- @file filter.lua
3 --- @brief Filter ...
4 --- @todo TODO docu
5 ---------------------------------
6 
7 local mod = {}
8 
9 local dpdkc = require "dpdkc"
10 local device = require "device"
11 local ffi = require "ffi"
12 local dpdk = require "dpdk"
13 local mbitmask = require "bitmask"
14 local err = require "error"
15 
16 mod.DROP = -1
17 
18 
19 local dev = device.__devicePrototype
20 
21 local deviceDependent = {}
22 deviceDependent[device.PCI_ID_X540] = require "filter_ixgbe"
23 deviceDependent[device.PCI_ID_X520] = require "filter_ixgbe"
24 deviceDependent[device.PCI_ID_82599] = require "filter_ixgbe"
25 deviceDependent[device.PCI_ID_XL710] = require "filter_i40e"
26 
27 
28 function dev:l2Filter(etype, queue)
29  if type(queue) == "table" then
30  if queue.dev.id ~= self.id then
31  error("Queue must belong to the device being configured")
32  end
33  queue = queue.qid
34  end
35  local fun = deviceDependent[self:getPciId()].l2Filter
36  if fun then
37  return fun(self, etype, queue)
38  else
39  errorf("l2Filter not supported, or not yet implemented for this device")
40  end
41 end
42 
43 --- Installs a 5tuple filter on the device.
44 --- Matching packets will be redirected into the specified rx queue
45 --- NOTE: this is currently only tested for X540 NICs, and will probably also
46 --- work for 82599 and other ixgbe NICs. Use on other NICs might result in
47 --- undefined behavior.
48 --- @param filter A table describing the filter. Possible fields are
49 --- src_ip : Sourche IPv4 Address
50 --- dst_ip : Destination IPv4 Address
51 --- src_port : Source L4 port
52 --- dst_port : Destination L4 port
53 --- l4protocol: L4 Protocol type
54 --- supported protocols: ip.PROTO_ICMP, ip.PROTO_TCP, ip.PROTO_UDP
55 --- If a non supported type is given, the filter will only match on
56 --- protocols, which are not supported.
57 --- All fields are optional.
58 --- If a field is not present, or nil, the filter will ignore this field when
59 --- checking for a match.
60 --- @param queue RX Queue, where packets, matching this filter will be redirected
61 --- @param priority optional (default = 1) The priority of this filter rule.
62 --- 7 is the highest priority and 1 the lowest priority.
63 function dev:addHW5tupleFilter(filter, queue, priority)
64  fun = deviceDependent[self:getPciId()].addHW5tupleFilter
65  if fun then
66  return fun(self, filter, queue, priority)
67  else
68  errorf("addHW5tupleFilter not supported, or not yet implemented for this device")
69  end
70 end
71 
72 --- Filter PTP time stamp packets by inspecting the PTP version and type field.
73 --- Packets with PTP version 2 are matched with this filter.
74 --- @param queue
75 --- @param offset the offset of the PTP version field
76 --- @param ntype the PTP type to look for, default = 0
77 --- @param ver the PTP version to look for, default = 2
78 function dev:filterTimestamps(queue, offset, ntype, ver)
79  -- TODO: dpdk only allows to change this at init time
80  -- however, I think changing the flex-byte offset field in the FDIRCTRL register can be changed at run time here
81  -- (as the fdir table needs to be cleared anyways which is the only precondition for changing this)
82  if type(queue) == "table" then
83  queue = queue.qid
84  end
85  offset = offset or 21
86  if offset ~= 21 then
87  error("other offsets are not yet supported")
88  end
89  mtype = mtype or 0
90  ver = ver or 2
91  local value = value or bit.lshift(ver, 8) + mtype
92  local filter = ffi.new("struct rte_fdir_filter")
93  filter.flex_bytes = value
94  filter.l4type = dpdkc.RTE_FDIR_L4TYPE_UDP
95  local mask = ffi.new("struct rte_fdir_masks")
96  mask.flexbytes = 1
97  dpdkc.rte_eth_dev_fdir_set_masks(self.id, mask)
98  dpdkc.rte_eth_dev_fdir_add_perfect_filter(self.id, filter, 1, queue, 0)
99 end
100 
101 
102 -- FIXME: add protp mask!!
103 ffi.cdef [[
104 struct mg_5tuple_rule {
105  uint8_t proto;
106  uint32_t ip_src;
107  uint8_t ip_src_prefix;
108  uint32_t ip_dst;
109  uint8_t ip_dst_prefix;
110  uint16_t port_src;
111  uint16_t port_src_range;
112  uint16_t port_dst;
113  uint16_t port_dst_range;
114 
115 };
116 
117 struct rte_acl_ctx * mg_5tuple_create_filter(int socket_id, uint32_t num_rules);
118 void mg_5tuple_destruct_filter(struct rte_acl_ctx * acl);
119 int mg_5tuple_add_rule(struct rte_acl_ctx * acx, struct mg_5tuple_rule * mgrule, int32_t priority, uint32_t category_mask, uint32_t value);
120 int mg_5tuple_build_filter(struct rte_acl_ctx * acx, uint32_t num_categories);
121 int mg_5tuple_classify_burst(
122  struct rte_acl_ctx * acx,
123  struct rte_mbuf **pkts,
124  struct mg_bitmask* pkts_mask,
125  uint32_t num_categories,
126  uint32_t num_real_categories,
127  struct mg_bitmask** result_masks,
128  uint32_t ** result_entries
129  );
130 uint32_t mg_5tuple_get_results_multiplier();
131 ]]
132 
133 local mg_filter_5tuple = {}
134 mod.mg_filter_5tuple = mg_filter_5tuple
135 mg_filter_5tuple.__index = mg_filter_5tuple
136 
137 --- Creates a new 5tuple filter / packet classifier
138 --- @param socket optional (default: socket of calling thread), CPU socket, where memory for the filter should be allocated.
139 --- @param acx experimental use only. should be nil.
140 --- @param numCategories number of categories, this filter should support
141 --- @param maxNRules optional (default = 10), maximum number of rules.
142 --- @return a wrapper table for the created filter
143 function mod.create5TupleFilter(socket, acx, numCategories, maxNRules)
144  socket = socket or select(2, dpdk.getCore())
145  maxNRules = maxNRules or 10
146 
147  local category_multiplier = ffi.C.mg_5tuple_get_results_multiplier()
148 
149  local rest = numCategories % category_multiplier
150 
151  local numBlownCategories = numCategories
152  if(rest ~= 0) then
153  numBlownCategories = numCategories + category_multiplier - rest
154  end
155 
156  local result = setmetatable({
157  acx = acx or ffi.gc(ffi.C.mg_5tuple_create_filter(socket, maxNRules), function(self)
158  -- FIXME: why is destructor never called?
159  print "5tuple garbage"
160  ffi.C.mg_5tuple_destruct_filter(self)
161  end),
162  built = false,
163  nrules = 0,
164  numCategories = numBlownCategories,
165  numRealCategories = numCategories,
166  out_masks = ffi.new("struct mg_bitmask*[?]", numCategories),
167  out_values = ffi.new("uint32_t*[?]", numCategories)
168  }, mg_filter_5tuple)
169 
170  for i = 1,numCategories do
171  result.out_masks[i-1] = nil
172  end
173  return result
174 end
175 
176 
177 --- Bind an array of result values to a filter category.
178 --- One array of values can be boun to multiple categories. After classification
179 --- it will contain mixed values of all categories it was bound to.
180 --- @param values Array of values to be bound to a category. May also be a number. In this case
181 --- a new Array will be allocated and bound to the specified category.
182 --- @param category optional (default = bind the specified array to all not yet bound categories),
183 --- The category the array should be bound to
184 --- @return the array, which was bound
185 function mg_filter_5tuple:bindValuesToCategory(values, category)
186  if type(values) == "number" then
187  values = ffi.new("uint32_t[?]", values)
188  end
189  if not category then
190  -- bind bitmask to all categories, which do not yet have an associated bitmask
191  for i = 1,self.numRealCategories do
192  if (self.out_values[i-1] == nil) then
193  print("assigned default at category " .. tostring(i))
194  self.out_values[i-1] = values
195  end
196  end
197  else
198  print("assigned bitmask to category " .. tostring(category))
199  self.out_values[category-1] = values
200  end
201  return values
202 end
203 
204 --- Bind a BitMask to a filter category.
205 --- On Classification the corresponding bits in the bitmask are set, when a rule
206 --- matches a packet, for the corresponding category.
207 --- One Bitmask can be bound to multiple categories. The result will be a bitwise OR
208 --- of the Bitmasks, which would be filled for each category.
209 --- @param bitmask Bitmask to be bound to a category. May also be a number. In this case
210 --- a new BitMask will be allocated and bound to the specified category.
211 --- @param category optional (default = bind the specified bitmask to all not yet bound categories),
212 --- The category the bitmask should be bound to
213 --- @return the bitmask, which was bound
214 function mg_filter_5tuple:bindBitmaskToCategory(bitmask, category)
215  if type(bitmask) == "number" then
216  bitmask = mbitmask.createBitMask(bitmask)
217  end
218  if not category then
219  -- bind bitmask to all categories, which do not yet have an associated bitmask
220  for i = 1,self.numRealCategories do
221  if (self.out_masks[i-1] == nil) then
222  print("assigned default at category " .. tostring(i))
223  self.out_masks[i-1] = bitmask.bitmask
224  end
225  end
226  else
227  print("assigned bitmask to category " .. tostring(category))
228  self.out_masks[category-1] = bitmask.bitmask
229  end
230  return bitmask
231 end
232 
233 
234 --- Allocates memory for one 5 tuple rule
235 --- @return ctype object "struct mg_5tuple_rule"
236 function mg_filter_5tuple:allocateRule()
237  return ffi.new("struct mg_5tuple_rule")
238 end
239 
240 --- Adds a rule to the filter
241 --- @param rule the rule to be added (ctype "struct mg_5tuple_rule")
242 --- @priority priority of the rule. Higher number -> higher priority
243 --- @category_mask bitmask for the categories, this rule should apply
244 --- @value 32bit integer value associated with this rule. Value is not allowed to be 0
245 function mg_filter_5tuple:addRule(rule, priority, category_mask, value)
246  if(value == 0) then
247  error("ERROR: Adding a rule with a 0 value is not allowed")
248  end
249  self.buit = false
250  return ffi.C.mg_5tuple_add_rule(self.acx, rule, priority, category_mask, value)
251 end
252 
253 --- Builds the filter with the currently added rules. Should be executed after adding rules
254 --- @param optional (default = number of Categories, set at 5tuple filter creation time) numCategories maximum number of categories, which are in use.
255 function mg_filter_5tuple:build(numCategories)
256  numCategories = numCategories or self.numRealCategories
257  self.built = true
258  --self.numCategories = numCategories
259  return ffi.C.mg_5tuple_build_filter(self.acx, numCategories)
260 end
261 
262 --- Perform packet classification for a burst of packets
263 --- Will do memory violation, when Masks or Values are not correctly bound to categories.
264 --- @param pkts Array of mbufs. Mbufs should contain valid IPv4 packets with a
265 --- normal ethernet header (no VLAN tags). A L4 Protocol header has to be
266 --- present, to avoid reading at invalid memory address. -- FIXME: check if this is true
267 --- @param inMask bitMask, specifying on which packets the filter should be applied
268 --- @return 0 on successfull completion.
269 function mg_filter_5tuple:classifyBurst(pkts, inMask)
270  if not self.built then
271  print("Warning: New rules have been added without building the filter!")
272  end
273  --numCategories = numCategories or self.numCategories
274  return ffi.C.mg_5tuple_classify_burst(self.acx, pkts.array, inMask.bitmask, self.numCategories, self.numRealCategories, self.out_masks, self.out_values)
275 end
276 return mod
277 
param n optional(default=2047)
Create a new memory pool.
local ffi
low-level dpdk wrapper
Definition: dpdkc.lua:6
function mg_filter_5tuple bindBitmaskToCategory(bitmask, category)
Bind a BitMask to a filter category.
function dev addHW5tupleFilter(filter, queue, priority)
Installs a 5tuple filter on the device.
function mg_filter_5tuple build(numCategories)
Builds the filter with the currently added rules.
function ipsecICV set(icv)
Set the IPsec ICV.
function mod new(n)
function mg_filter_5tuple classifyBurst(pkts, inMask)
Perform packet classification for a burst of packets Will do memory violation, when Masks or Values a...
ip PROTO_ICMP
Protocol field value for Icmp.
Definition: ip4.lua:28
ip PROTO_TCP
Protocol field value for Tcp.
Definition: ip4.lua:30
local mod
high-level dpdk wrapper
Definition: dpdk.lua:6
function dev filterTimestamps(queue, offset, ntype, ver)
Filter PTP time stamp packets by inspecting the PTP version and type field.
function mod init()
Inits DPDK. Called by MoonGen on startup.
function ip4Addr add(val)
Add a number to an IPv4 address in-place.
function mg_filter_5tuple addRule(rule, priority, category_mask, value)
Adds a rule to the filter.
function mod createBitMask(size)
Create a Bitmask The mask is internally built from blocks of 64bit integers.
function mg_filter_5tuple bindValuesToCategory(values, category)
Bind an array of result values to a filter category.
ip PROTO_UDP
Protocol field value for Udp.
Definition: ip4.lua:32
local ip
IP4 protocol constants.
Definition: ip4.lua:25
function errorf(str,...)
Print a formatted error string.
function mg_filter_5tuple allocateRule()
Allocates memory for one 5 tuple rule.