1 /*
2 ** Copyright (C) 2004-2020 by Carnegie Mellon University.
3 **
4 ** @OPENSOURCE_LICENSE_START@
5 ** See license information in ../../LICENSE.txt
6 ** @OPENSOURCE_LICENSE_END@
7 */
8 
9 /*
10 **  skbag.h
11 **
12 **    The Bag API maps keys to counters.
13 **
14 **    For keys of 32-bits or less, the data structure is a tree whose
15 **    depth depends on the number of octets in the key.  A key's value
16 **    is encoded into the tree's structure.  At the leaves, the tree
17 **    contains blocks of counters to hold the counter associated with
18 **    a key.
19 **
20 **    The API defined in this file is current as of SiLK 3.0.
21 **
22 **    As of SiLK 3.0, some older functions and types have been
23 **    deprecated.  Those functions and types are declared in the
24 **    header file silk/bagtree.h.
25 **
26 **    Original implementation:
27 **      Christopher Lee
28 **      2004-11-04
29 **
30 **
31 */
32 #ifndef _SKBAG_H
33 #define _SKBAG_H
34 #ifdef __cplusplus
35 extern "C" {
36 #endif
37 
38 #include <silk/silk.h>
39 
40 RCSIDENTVAR(rcsID_SKBAG_H, "$SiLK: skbag.h ef14e54179be 2020-04-14 21:57:45Z mthomas $");
41 
42 #include <silk/silk_types.h>
43 
44 /**
45  *  @file
46  *
47  *    A mapping from a key to a counter.  The key can be a 8, 16, or
48  *    32 bit integer or an IPv4 or IPv6 address.  The counter is an
49  *    unsigned 64 bit value.
50  *
51  *    This file is part of libsilk.
52  */
53 
54 
55 /* DEFINES AND TYPEDEFS */
56 
57 /**
58  *    The Bag object maps keys to counters
59  */
60 typedef struct skBag_st skBag_t;
61 
62 
63 /**
64  *    Nearly every Bag function returns one of the following values to
65  *    denote the status of invoking the function.
66  */
67 typedef enum skBagErr_en {
68     /** Success */
69     SKBAG_OK = 0,
70     /** Memory allocation error */
71     SKBAG_ERR_MEMORY = 1,
72     /** No more entries in bag */
73     SKBAG_ERR_KEY_NOT_FOUND = 2,
74     /** Invalid argument to function */
75     SKBAG_ERR_INPUT = 3,
76     /** Overflow/Underflow in counter */
77     SKBAG_ERR_OP_BOUNDS = 4,
78     /** Error writing to stream */
79     SKBAG_ERR_OUTPUT = 5,
80     /** Error reading from stream */
81     SKBAG_ERR_READ = 6,
82     /** File header values incompatible with this compile of SiLK */
83     SKBAG_ERR_HEADER = 7,
84     /** Key out of range for bag and auto-conversion disabled */
85     SKBAG_ERR_KEY_RANGE = 8,
86     /** Bag modified during iteration */
87     SKBAG_ERR_MODIFIED = 9
88 } skBagErr_t;
89 
90 
91 /**
92  *    The following structure is used to iterate over the key/counter
93  *    pairs in a Bag.
94  */
95 typedef struct skBagIterator_st skBagIterator_t;
96 
97 
98 /**
99  *    The Bag API supports adding keys and counters whose types are
100  *    one of an enumerated set of values.  When setting or getting a
101  *    key or counter, the caller must specify the type of key or
102  *    counter the caller is providing or wants to receive.
103  *
104  *    When getting a key or counter, the caller may specify the
105  *    special ANY type to have the Bag return the "natural" type for
106  *    the data structure; the Bag sets the type to the type of
107  *    value returned.
108  *
109  *    The following enumerations list the types for keys and
110  *    counters.
111  */
112 typedef enum skBagKeyType_en {
113     SKBAG_KEY_ANY     = 0,
114     SKBAG_KEY_U8      = 1,
115     SKBAG_KEY_U16     = 2,
116     SKBAG_KEY_U32     = 4,
117     SKBAG_KEY_IPADDR  = 16
118 } skBagKeyType_t;
119 
120 typedef enum skBagCounterType_en {
121     SKBAG_COUNTER_ANY     = 0,
122     SKBAG_COUNTER_U64     = 8
123 } skBagCounterType_t;
124 
125 
126 /**
127  *    The following types specify how keys and counters are to be
128  *    provided to and received from the Bag, as of SiLK 3.0.
129  */
130 typedef struct skBagTypedKey_st {
131     skBagKeyType_t              type;
132     union skBagTypedKey_un {
133         uint8_t     u8;
134         uint16_t    u16;
135         uint32_t    u32;
136         uint64_t    u64; /* unsupported */
137         skipaddr_t  addr;
138     }                           val;
139 } skBagTypedKey_t;
140 
141 typedef struct skBagTypedCounter_st {
142     skBagCounterType_t          type;
143     union skBagTypedCounter_un {
144         uint64_t    u64;
145     }                           val;
146 } skBagTypedCounter_t;
147 
148 
149 /*
150  *    The older SiLK 2.x Bag API (see bagtree.h) used a fixed size for
151  *    the key and counter stored in the bag.  Those types are defined
152  *    here.
153  */
154 
155 typedef uint32_t skBagKey_t;
156 typedef uint64_t skBagCounter_t;
157 
158 
159 /*
160  *    The following specify the numeric range of counters in a Bag.
161  *
162  *    Note that the maximum counter in SiLK 3.0 is less than that in
163  *    SiLK 2.0.
164  *
165  *    Although SKBAG_COUNTER_MIN is 0, setting the counter of a key is
166  *    0 effectively removes the key from the bag.
167  */
168 
169 #define SKBAG_COUNTER_MIN   UINT64_C(0)
170 #define SKBAG_COUNTER_MAX   (UINT64_MAX - UINT64_C(1))
171 
172 
173 /*
174  *    The following specify the numeric range of keys in a Bag that
175  *    does not hold IPv6 addresses.
176  */
177 
178 #define SKBAG_KEY_MIN       UINT32_C(0)
179 #define SKBAG_KEY_MAX       UINT32_MAX
180 
181 
182 /**
183  *    The Bag data-structure maintains a key-type and counter-type
184  *    that specify what the key and counter represent.  For example, a
185  *    Bag could map each source-port value to the number of flows seen
186  *    for that port.
187  *
188  *    The following enumeration lists those types.
189  */
190 typedef enum skBagFieldType_en {
191     /* the following correspond to values in rwascii.h */
192     SKBAG_FIELD_SIPv4 = 0,
193     SKBAG_FIELD_DIPv4,
194     SKBAG_FIELD_SPORT,
195     SKBAG_FIELD_DPORT,
196     SKBAG_FIELD_PROTO = 4,
197     SKBAG_FIELD_PACKETS,
198     SKBAG_FIELD_BYTES,
199     SKBAG_FIELD_FLAGS,
200     SKBAG_FIELD_STARTTIME = 8,
201     SKBAG_FIELD_ELAPSED,
202     SKBAG_FIELD_ENDTIME,
203     SKBAG_FIELD_SID,
204     SKBAG_FIELD_INPUT = 12,
205     SKBAG_FIELD_OUTPUT,
206     SKBAG_FIELD_NHIPv4,
207     SKBAG_FIELD_INIT_FLAGS,
208     SKBAG_FIELD_REST_FLAGS = 16,
209     SKBAG_FIELD_TCP_STATE,
210     SKBAG_FIELD_APPLICATION,
211     SKBAG_FIELD_FTYPE_CLASS,
212     SKBAG_FIELD_FTYPE_TYPE = 20,
213     /*
214      *  SKBAG_FIELD_STARTTIME_MSEC = 21,
215      *  SKBAG_FIELD_ENDTIME_MSEC,
216      *  SKBAG_FIELD_ELAPSED_MSEC,
217      */
218     SKBAG_FIELD_ICMP_TYPE_CODE = 24,
219     /* the above correspond to values in rwascii.h */
220 
221     SKBAG_FIELD_SIPv6,
222     SKBAG_FIELD_DIPv6,
223     SKBAG_FIELD_NHIPv6,
224     SKBAG_FIELD_RECORDS = 28,
225     SKBAG_FIELD_SUM_PACKETS,
226     SKBAG_FIELD_SUM_BYTES,
227     SKBAG_FIELD_SUM_ELAPSED,
228 
229     SKBAG_FIELD_ANY_IPv4 = 32,
230     SKBAG_FIELD_ANY_IPv6,
231     SKBAG_FIELD_ANY_PORT,
232     SKBAG_FIELD_ANY_SNMP,
233     SKBAG_FIELD_ANY_TIME = 36,
234 
235     SKBAG_FIELD_SIP_COUNTRY,
236     SKBAG_FIELD_DIP_COUNTRY,
237     SKBAG_FIELD_ANY_COUNTRY,
238 
239     SKBAG_FIELD_SIP_PMAP = 40,
240     SKBAG_FIELD_DIP_PMAP,
241     SKBAG_FIELD_ANY_IP_PMAP,
242 
243     SKBAG_FIELD_SPORT_PMAP,
244     SKBAG_FIELD_DPORT_PMAP = 44,
245     SKBAG_FIELD_ANY_PORT_PMAP = 45,
246 
247     SKBAG_FIELD_CUSTOM = 255
248 } skBagFieldType_t;
249 
250 
251 /**
252  *    The following structure is used to iterate over the field types
253  *    listed above.
254  *
255  *    The structure is defined here so that the iterator may be
256  *    created on the stack.  However, the structure is subject to
257  *    change and the caller should treat the interals of this
258  *    structure as opaque.
259  */
260 typedef struct skBagFieldTypeIterator_st {
261     skBagFieldType_t    val;
262     uint8_t             no_more_entries;
263 } skBagFieldTypeIterator_t;
264 
265 
266 /**
267  *    In skBagCounterFieldName(), skBagFieldTypeAsString(), and
268  *    skBagKeyFieldName(), using a character buffer of at least this
269  *    size is guaranteed to hold all the possible field type strings.
270  */
271 #define SKBAG_MAX_FIELD_BUFLEN  32
272 
273 
274 /**
275  *    Value returned by skBagFieldTypeGetLength() when the field type
276  *    is SKBAG_FIELD_CUSTOM.
277  */
278 #define SKBAG_OCTETS_CUSTOM         (SIZE_MAX-1)
279 
280 
281 /**
282  *    Value returned by skBagFieldTypeGetLength() when the field type
283  *    is not recognized.
284  */
285 #define SKBAG_OCTETS_UNKNOWN        SIZE_MAX
286 
287 
288 /**
289  *    In skBagCreateTyped() and skBagModify(), the value to use for
290  *    'key_octets' or 'counter_octets' that indicates the size should
291  *    be the default size for the 'key_type' or 'counter_type',
292  *    respectively.
293  */
294 #define SKBAG_OCTETS_FIELD_DEFAULT  0
295 
296 
297 /**
298  *    In skBagModify(), the value to use for 'key_octets' or
299  *    'counter_octets' that indicates the size should remain
300  *    unchagned.
301  */
302 #define SKBAG_OCTETS_NO_CHANGE      (SIZE_MAX-2)
303 
304 
305 /**
306  *    The signature of a callback used by skBagAddBag() when adding
307  *    two counters causes an overflow.
308  *
309  *    The value in 'key' is the key where the overflow is occuring,
310  *    'in_out_counter' is the current value of the counter in the
311  *    destination bag, 'in_counter' is the current value in the source
312  *    bag, and 'cb_data' is the caller-supplied parameter to
313  *    skBagAddBag().
314  *
315  *    The callback should modify 'in_out_counter' to the value the
316  *    caller wants to insert into the destination bag for 'key'.  If
317  *    the callback returns any value other than SKBAG_OK,
318  *    skBagAddBag() stops processing and returns that value.
319  */
320 typedef skBagErr_t
321 (*skBagBoundsCallback_t)(
322     const skBagTypedKey_t      *key,
323     skBagTypedCounter_t        *in_out_counter,
324     const skBagTypedCounter_t  *in_counter,
325     void                       *cb_data);
326 
327 
328 /**
329  *    The signature of a callback used by skBagProcessStreamTyped()
330  *    when reading a bag from a stream.  This callback is invoked
331  *    after the stream's header has been read and before processing
332  *    any entries in the bag.
333  *
334  *    If this function returns a value other than SKBAG_OK, processing
335  *    of the bag stops.
336  *
337  *    The 'fake_bag' argument is partially constructed bag that may
338  *    be used to query the type and/or size of the key and counter in
339  *    the bag that is being read.  This parameter must be considered
340  *    read-only.
341  *
342  *    The 'cb_data' parameter is provided for the caller to use.  It
343  *    is the parameter specified to skBagProcessStream().
344  */
345 typedef skBagErr_t
346 (*skBagStreamInitFunc_t)(
347     const skBag_t          *fake_bag,
348     void                   *cb_data);
349 
350 
351 /**
352  *    The signature of a callback used by skBagProcessStreamTyped()
353  *    when reading a bag from a stream.  This callback is invoked for
354  *    each entry (that is, each key/counter pair) read from the bag.
355  *
356  *    The 'fake_bag' argument is partially constructed bag that may be
357  *    used to query the type and/or size of the key and counter in the
358  *    bag that is being read.  This parameter must be considered
359  *    read-only.
360  *
361  *    The 'key' parameter is a pointer to the current key.  If the bag
362  *    contains IPv6 addresses, the type of the key is
363  *    SKBAG_KEY_IPADDR.  Otherwise, the type of the key is
364  *    SKBAG_KEY_U32.
365  *
366  *    The 'counter' paramter is a pointer to the current counter.
367  *
368  *    The 'cb_data' parameter is provided for the caller to use.  It
369  *    is the parameter specified to skBagProcessStream().
370  */
371 typedef skBagErr_t
372 (*skBagStreamEntryFunc_t)(
373     const skBag_t              *fake_bag,
374     const skBagTypedKey_t      *key,
375     const skBagTypedCounter_t  *counter,
376     void                       *cb_data);
377 
378 
379 /**
380  *    Some features of the Bag are implemented as macros, and those
381  *    macros use the following variables.  The variables are not
382  *    considered part of the supported API, and they are not for
383  *    public use.
384  */
385 extern const skBagTypedCounter_t *skbag_counter_zero;
386 extern const skBagTypedCounter_t *skbag_counter_incr;
387 
388 
389 /* FUNCTION DECLARATIONS */
390 
391 /**
392  *    Add the key/counter pairs of the in-memory bag 'src_bag' to the
393  *    in-memory bag 'dest_bag', in effect 'dest_bag' += 'src_bag'.
394  *
395  *    The key_type, counter_type, key_octets, and counter_octets of
396  *    'dest_bag' may change as a result of this operation.
397  *
398  *    The 'bounds_cb' callback may be NULL.  When it is specified, it
399  *    is invoked whenever summing two counters causes an overflow
400  *    (that is, when skBagCounterAdd() returns SKBAG_ERR_OP_BOUNDS).
401  *    The callback is invoked with the key, the counter from
402  *    'dest_bag', the counter from 'src_bag', and the 'cb_data'.  The
403  *    callback should modify the counter from 'dest_bag' to the value
404  *    the caller wants to insert into 'dest_bag' and return SKBAG_OK,
405  *    and the function then attempts to set the key in 'dest_bag'
406  *    to that value.  If the insert succeeds, processing continues;
407  *    otherwise the result of the attempt to set the key is
408  *    returned.  If 'bounds_cb' returns a value other than SKBAG_OK,
409  *    that value is returned.
410  *
411  *    Return SKBAG_OK on success.  Return SKBAG_ERR_INPUT if
412  *    'dest_bag' or 'src_bag' is NULL.  Return SKBAG_ERR_KEY_RANGE if
413  *    the key octet width in 'src' is larger than that in 'dest' and
414  *    auto-conversion is disabled in 'dest'.  Return SKBAG_ERR_MEMORY
415  *    if a key cannot be inserted into 'dest_bag'.  Return
416  *    SKBAG_ERR_OP_BOUNDS if adding two counters causes an overflow
417  *    and the 'bounds_cb' callback parameter is NULL.
418  */
419 skBagErr_t
420 skBagAddBag(
421     skBag_t                *dest,
422     const skBag_t          *src,
423     skBagBoundsCallback_t   bounds_cb,
424     void                   *cb_data);
425 
426 
427 /**
428  *    Read a serialized Bag from the input stream 'stream' and add
429  *    its key/counter pairs to the existing Bag 'bag'.  New keys are
430  *    created if required; existing keys have their values
431  *    summed.
432  *
433  *    Return SKBAG_ERR_INPUT if 'bag' or 'stream_in' is NULL.  Return
434  *    SKBAG_ERR_OP_BOUNDS if summing counters results in an overflow.
435  *    Return SKBAG_ERR_KEY_RANGE if auto-conversion is disabled on
436  *    'bag' (see skBagAutoConvertDisable()) and the key size in 'bag'
437  *    is smaller than the key size of the bag in 'stream_in'.
438  */
439 skBagErr_t
440 skBagAddFromStream(
441     skBag_t            *bag,
442     skstream_t         *stream_in);
443 
444 
445 /**
446  *    Prevent auto-conversion of keys from happening on 'bag'.
447  *
448  *    By default, attempting to insert a key whose octet width is
449  *    larger than the Bag current supports promotes the keys in the
450  *    Bag to hold the larger key.  Such an auto-conversion may occur
451  *    when inserting an IPv6 address into a uint32_t Bag, or when
452  *    inserting a uint32_t key into an uint8_t Bag.  This function
453  *    disables this conversion.  An attempt to insert an unsupported
454  *    key size into such a Bag returns SKBAG_ERR_KEY_RANGE.
455  *
456  *    See also skBagAutoConvertEnable() and
457  *    skBagAutoConvertIsEnabled().
458  */
459 void
460 skBagAutoConvertDisable(
461     skBag_t            *bag);
462 
463 
464 /**
465  *    Allow an attempt to insert a key whose octet width is larger
466  *    than 'bag' currently support to succeed, promoting the keys in
467  *    'bag' to the wider size.  This behavior is the default.
468  *
469  *    See also skBagAutoConvertDisable() and
470  *    skBagAutoConvertIsEnabled().
471  */
472 void
473 skBagAutoConvertEnable(
474     skBag_t            *bag);
475 
476 
477 /**
478  *    Return 1 if 'bag' automatically converts its keys' octet width
479  *    to a larger size when an attempt is made to insert a larger key.
480  *
481  *    See also skBagAutoConvertDisable() and
482  *    skBagAutoConvertEnable().
483  */
484 int
485 skBagAutoConvertIsEnabled(
486     const skBag_t      *bag);
487 
488 
489 /**
490  *    Make a new bag that is a deep copy of src, and set the referent
491  *    of 'dest' to it.
492  */
493 skBagErr_t
494 skBagCopy(
495     skBag_t           **dest,
496     const skBag_t      *src);
497 
498 
499 /**
500  *    Return the number of unique keys in 'bag'.
501  */
502 uint64_t
503 skBagCountKeys(
504     const skBag_t      *bag);
505 
506 
507 /**
508  *    In 'bag', add to the counter associated with 'key' the value
509  *    'counter_add'.  If 'key' does not exist in 'bag', insert it into
510  *    'bag' and set its value to 'counter_add'.
511  *
512  *    If 'key' is larger than the maximum key currently supported by
513  *    'bag', 'bag' is converted to a size capable of holding 'key'
514  *    unless auto-conversion is disabled for 'bag'; see
515  *    skBagAutoConvertEnable(), skBagAutoConvertDisable(), and
516  *    skBagAutoConvertIsEnabled().
517  *
518  *    If 'new_counter' is not NULL, the new value of the counter is
519  *    copied into that location.  'new_counter' is unchanged when this
520  *    function turns a value other than SKBAG_OK.
521  *
522  *    Return SKBAG_OK on success.  Return SKBAG_ERR_MEMORY if the
523  *    attempt to insert the key fails because of an allocation error.
524  *    Return SKBAG_ERR_KEY_RANGE if the value in 'key' is larger than
525  *    the octet width in 'bag' and auto-conversion is disabled in
526  *    'bag'.  If the addition would cause the counter to overflow, the
527  *    current value in 'bag' remains unchanged and SKBAG_ERR_OP_BOUNDS
528  *    is returned.  Return SKBAG_ERR_INPUT if any input parameter
529  *    (other than 'new_counter') is NULL, if the type of 'key' is
530  *    SKBAG_KEY_ANY, if the type of 'counter' is SKBAG_COUNTER_ANY, or
531  *    if 'counter' is larger than SKBAG_COUNTER_MAX.
532  *
533  *    See also skBagCounterSet() and skBagCounterSubtract().  The
534  *    convenience wrapper skBagCounterIncrement() may be used to add 1
535  *    to a key's counter.  Use skBagCounterGet() to get a key's
536  *    counter.
537  */
538 skBagErr_t
539 skBagCounterAdd(
540     skBag_t                    *bag,
541     const skBagTypedKey_t      *key,
542     const skBagTypedCounter_t  *counter_add,
543     skBagTypedCounter_t        *new_counter);
544 
545 
546 /**
547  *    In 'bag', decrement the counter associated with 'key' by one.
548  *    This is no-op if 'key' does not exist in 'bag'; that is, unlike
549  *    skBagCounterSubtract(), this macro returns SKBAG_OK if 'key' is
550  *    not in 'bag'.
551  */
552 #define skBagCounterDecrement(dec_bag, dec_key)         \
553     ((skBagCounterSubtract((dec_bag), (dec_key),        \
554                            skbag_counter_incr, NULL)    \
555       == SKBAG_ERR_INPUT)                               \
556      ? SKBAG_ERR_INPUT : SKBAG_OK)
557 
558 
559 /**
560  *    Return the number of octets the counter of 'bag' occupies
561  *    for the in-core representation of 'bag'.
562  */
563 size_t
564 skBagCounterFieldLength(
565     const skBag_t      *bag);
566 
567 
568 /**
569  *    Return the type of counter that 'bag' contains, and, if 'buf' is
570  *    not NULL, fill 'buf' with a string representation of that type.
571  *    The caller must specify the size of 'buf' in 'buflen'.  If 'buf'
572  *    is too small to hold the string representation, 'buf' is filled
573  *    with as much of the name as possible.
574  *
575  *    See also skBagCounterFieldType(), skBagKeyFieldName(), and
576  *    skBagKeyFieldType().
577  */
578 skBagFieldType_t
579 skBagCounterFieldName(
580     const skBag_t      *bag,
581     char               *buf,
582     size_t              buflen);
583 
584 
585 /**
586  *    Return the type of counter that 'bag' contains.
587  *
588  *    See also skBagCounterFieldName(), skBagKeyFieldType(), and
589  *    skBagKeyFieldName().
590  */
591 skBagFieldType_t
592 skBagCounterFieldType(
593     const skBag_t      *bag);
594 
595 
596 /**
597  *    Fill 'counter' with the value associated with 'key' in 'bag'.
598  *    If 'key' is not in bag, set 'counter' to 0.  Return SKBAG_OK and
599  *    set 'counter' to 0 when 'key' is outside the range supported by
600  *    'bag'.
601  *
602  *    Return SKBAG_OK on success, or SKBAG_ERR_INPUT when any input
603  *    parameter is NULL or when the type of 'key' or 'counter' is not
604  *    recognized.
605  *
606  *    Use skBagCounterSet() to set a key's counter.  See also
607  *    skBagCounterAdd() and skBagCounterSubtract().
608  */
609 skBagErr_t
610 skBagCounterGet(
611     const skBag_t          *bag,
612     const skBagTypedKey_t  *key,
613     skBagTypedCounter_t    *counter);
614 
615 
616 /**
617  *    In 'bag', increment the counter associated with 'key' by one.
618  *    Create the key and set its counter to 1 if the key does not
619  *    exist in the bag.
620  *
621  *    This is a convenience wrapper around skBagCounterAdd(), which
622  *    see for additional information.
623  */
624 #define skBagCounterIncrement(inc_bag, inc_key)                      \
625     skBagCounterAdd((inc_bag), (inc_key), skbag_counter_incr, NULL)
626 
627 
628 /**
629  *    In 'bag', set the counter associated with 'key' to the value
630  *    'counter'.  If 'counter' is non-zero, create 'key' if it does
631  *    not already exist in 'bag'.  If 'counter' is 0, remove 'key' if
632  *    it exists in 'bag'; otherwise, do nothing.
633  *
634  *    If 'key' is larger than the maximum key currently supported by
635  *    'bag', 'bag' is converted to a size capable of holding 'key'
636  *    unless auto-conversion in 'bag' is disabled; see
637  *    skBagAutoConvertEnable(), skBagAutoConvertDisable(), and
638  *    skBagAutoConvertIsEnabled().
639  *
640  *    Return SKBAG_OK on success.  Return SKBAG_ERR_MEMORY if there is
641  *    an allocation error when inserting the 'key'.  Unless 'counter'
642  *    is 0, return SKBAG_ERR_KEY_RANGE if the value in 'key' is larger
643  *    than the octet width in 'bag' and auto-conversion is disabled in
644  *    'bag'.  Return SKBAG_ERR_INPUT if any input parameter is NULL,
645  *    if the type of 'key' is SKBAG_KEY_ANY, if the type of 'counter'
646  *    is SKBAG_COUNTER_ANY, or if 'counter' is larger than
647  *    SKBAG_COUNTER_MAX.
648  *
649  *    See also skBagCounterAdd() and skBagCounterSubtract().  Use
650  *    skBagCounterGet() to get a key's counter.
651  */
652 skBagErr_t
653 skBagCounterSet(
654     skBag_t                    *bag,
655     const skBagTypedKey_t      *key,
656     const skBagTypedCounter_t  *counter);
657 
658 
659 /**
660  *    In 'bag', subtract from the counter associated with 'key' the
661  *    value 'counter_sub'.  When 'counter_sub' is non-zero, 'key' must
662  *    exist in 'bag'; if it does not, SKBAG_ERR_OP_BOUNDS is returned.
663  *    SKBAG_ERR_OP_BOUNDS is also returned when 'key' is outside the
664  *    range of keys supported by 'bag'.
665  *
666  *    When 'counter_sub' is 0, return SKBAG_OK regardless of whether
667  *    'key' is in 'bag' and, if 'new_counter' is not NULL, set it to
668  *    the counter for 'key' if 'key' is in 'bag' or 0 otherwise.
669  *
670  *    If 'new_counter' is not NULL, the new value of the counter is
671  *    copied into that location.  'new_counter' is unchanged when this
672  *    function turns a value other than SKBAG_OK.
673  *
674  *    Return SKBAG_OK on success.  If the subtraction would cause the
675  *    counter to become negative or if 'key' does not exist in 'bag',
676  *    the counter in 'bag' is unchanged and SKBAG_ERR_OP_BOUNDS is
677  *    returned.  Return SKBAG_ERR_INPUT if any input parameter is
678  *    NULL, if the type of 'key' is SKBAG_KEY_ANY, if the type of
679  *    'counter' is SKBAG_COUNTER_ANY, or if 'counter' is larger than
680  *    SKBAG_COUNTER_MAX.
681  *
682  *    See also skBagCounterSet() and skBagCounterAdd().  The
683  *    convenience wrapper skBagCounterDecrement() may be used to
684  *    subtract 1 from a key's counter.  Use skBagCounterGet() to
685  *    get a key's counter.
686  */
687 skBagErr_t
688 skBagCounterSubtract(
689     skBag_t                    *bag,
690     const skBagTypedKey_t      *key,
691     const skBagTypedCounter_t  *counter_sub,
692     skBagTypedCounter_t        *new_counter);
693 
694 
695 /**
696  *    Allocate memory for a new Bag and set the referent of 'bag' to
697  *    it.  The type of the key and counter are set to
698  *    SKBAG_FIELD_CUSTOM.  The bag is created with a 4 octet key and
699  *    an 8 octet counter.
700  *
701  *    See also skBagCreateTyped().
702  */
703 skBagErr_t
704 skBagCreate(
705     skBag_t           **bag);
706 
707 
708 /**
709  *    Allocate memory for a new Bag to hold a specific type of key and
710  *    counter, each having the specified number of octets.  Set the
711  *    referent of 'bag' to the newly allocated bag.
712  *
713  *    When 'key_type' is SKBAG_FIELD_CUSTOM, the value in 'key_octets'
714  *    must be one of the supported key lengths.  Currently, the
715  *    supported values for 'key_octets' are 1,2,4,16.  Note that
716  *    'key_octets' of 8 is not supported.
717  *
718  *    When 'key_type' is not SKBAG_FIELD_CUSTOM, the value in
719  *    'key_octets' must be a supported key length or the value may be
720  *    SKBAG_OCTETS_FIELD_DEFAULT, indicating the bag should use the
721  *    size returned by skBagFieldTypeGetLength('key_type').  If that
722  *    function returns a length of 8, the bag uses a length of 4
723  *    instead.
724  *
725  *    When 'counter_type' is SKBAG_FIELD_CUSTOM, the value in
726  *    'counter_octets' must be specified as 8, as currently that is
727  *    the only supported value for 'counter_octets'.
728  *
729  *    When 'counter_type' is not SKBAG_FIELD_CUSTOM, 'counter_octets'
730  *    value must be either 8 or SKBAG_OCTETS_FIELD_DEFAULT.  The bag
731  *    will use a 'counter_octets' value of 8.
732  *
733  *    The function returns SKBAG_OK on success.  It returns
734  *    SKBAG_ERR_MEMORY if the bag cannot be allocated.  A return value
735  *    of SKBAG_ERR_INPUT indicates the 'bag' parameter was NULL, the
736  *    'key_type' or 'counter_type' was not recognized, or the
737  *    'key_octets' or 'counter_octets' are not a supported value.
738  */
739 skBagErr_t
740 skBagCreateTyped(
741     skBag_t           **bag,
742     skBagFieldType_t    key_type,
743     skBagFieldType_t    counter_type,
744     size_t              key_octets,
745     size_t              counter_octets);
746 
747 
748 /**
749  *    Free all memory associated with the Bag pointed to by 'bag' and
750  *    set '*bag' to NULL.  This function does nothing when 'bag' is
751  *    NULL or the memory that 'bag' points to is NULL.
752  */
753 void
754 skBagDestroy(
755     skBag_t           **bag);
756 
757 
758 /**
759  *    Fill 'buf' with a string representation of the field-type
760  *    'field'.  The caller must specify the size of 'buf' in 'buflen'.
761  *    Return the value 'buf' when 'field' is a valid field type and
762  *    'buflen' is large enough to hold the complete type name.
763  *    Otherwise leave 'buf' unchanged and return NULL.
764  */
765 char *
766 skBagFieldTypeAsString(
767     skBagFieldType_t    field,
768     char               *buf,
769     size_t              buflen);
770 
771 
772 /**
773  *    Return the standard number of octets required to hold the
774  *    field-type 'field'.  Return SKBAG_OCTETS_CUSTOM if the field
775  *    type is SKBAG_FIELD_CUSTOM.  Return SKBAG_OCTETS_UNKNOWN if
776  *    'field' is not recognized.
777  */
778 size_t
779 skBagFieldTypeGetLength(
780     skBagFieldType_t    field);
781 
782 
783 /**
784  *    Bind the iterator 'ft_iter' to iterate over the skBagFieldType_t
785  *    values that this bag library supports.  Return SKBAG_OK unless
786  *    'ft_iter' is NULL.
787  */
788 skBagErr_t
789 skBagFieldTypeIteratorBind(
790     skBagFieldTypeIterator_t   *ft_iter);
791 
792 
793 /**
794  *    Move the iterator to the next skBagFieldType_t value.  Return
795  *    SKBAG_OK on success; return SKBAG_ERR_KEY_NOT_FOUND if there are
796  *    no more field types to vist; return SKBAG_ERR_INPUT if 'iter' is
797  *    NULL.
798  *
799  *    If 'field_id' is not NULL, fill it with the skBagFieldType_t
800  *    value.  If 'field_octets' is not NULL, fill it with the number
801  *    of octets normally used by that field.  If 'field_name' is not
802  *    NULL and 'field_name_len' is large enough to hold the entire
803  *    field name, fill 'field_name' with the string representation of
804  *    the type.
805  */
806 skBagErr_t
807 skBagFieldTypeIteratorNext(
808     skBagFieldTypeIterator_t   *iter,
809     skBagFieldType_t           *field_id,
810     size_t                     *field_octets,
811     char                       *field_name,
812     size_t                      field_name_len);
813 
814 
815 /**
816  *    Reset 'iter' so it will revisit the skBagFieldType_t values.
817  */
818 skBagErr_t
819 skBagFieldTypeIteratorReset(
820     skBagFieldTypeIterator_t   *iter);
821 
822 
823 /**
824  *    Find the field-type whose name is the string 'type_name'.  If
825  *    'type_name' is not a valid field-type name, return
826  *    SKBAG_ERR_INPUT; otherwise return SKBAG_OK.
827  *
828  *    If the argument 'field_type' is not NULL, fill its referent with
829  *    the ID corresponding to 'name'.  If the argument 'field_octets'
830  *    is not NULL, fill its referent with the number of octets that
831  *    field normally occupies---that is, the result of calling
832  *    skBagFieldTypeGetLength() on the field.
833  */
834 skBagErr_t
835 skBagFieldTypeLookup(
836     const char         *type_name,
837     skBagFieldType_t   *field_type,
838     size_t             *field_length);
839 
840 
841 /**
842  *    Return the field type that should be used when two bags are
843  *    merged.
844  *
845  *    This function assumes the bags are being added or subtracted.
846  */
847 skBagFieldType_t
848 skBagFieldTypeMerge(
849     skBagFieldType_t    field_type1,
850     skBagFieldType_t    field_type2);
851 
852 
853 /**
854  *    Create a new iterator to iterate over the bag 'bag' and store
855  *    the iterator in the referent of 'iter'.  The iterator is
856  *    initialized so that the first call to skBagIteratorNextTyped()
857  *    returns the counter associated with the first key.
858  *
859  *    If the key size of the bag changes during iteration,
860  *    SKBAG_ERR_MODIFIED is returned.  At that point, the
861  *    iterator may be destroyed or reset.
862  *
863  *    If keys are added or removed during iteration, the entries may
864  *    or may not be visited by the iterator.
865  *
866  *    The iterator visits the entries in 'bag' in order from the
867  *    smallest key to the largest key.
868  *
869  *    Once iteration is complete, the caller must destroy the iterator
870  *    by calling skBagIteratorDestroy().
871  */
872 skBagErr_t
873 skBagIteratorCreate(
874     const skBag_t      *bag,
875     skBagIterator_t   **iter);
876 
877 
878 /**
879  *    Similar to skBagIteratorCreate(), but the iterator does not make
880  *    any guarantees on the order in which the iterator visits the
881  *    entries.
882  */
883 skBagErr_t
884 skBagIteratorCreateUnsorted(
885     const skBag_t      *bag,
886     skBagIterator_t   **iter);
887 
888 
889 /**
890  *    Deallocate all memory associated with the bag iterator 'iter'.
891  *    The function returns SKBAG_ERR_INPUT if the 'iter' parameter is
892  *    NULL.
893  */
894 skBagErr_t
895 skBagIteratorDestroy(
896     skBagIterator_t    *iter);
897 
898 
899 /**
900  *    Get the next key/counter pair associated with the given
901  *    iterator, 'iter', store them in the referents of
902  *    'key' and 'counter', respectively, and return SKBAG_OK.
903  *
904  *    The 'type' field of 'key' and 'counter' structures determine how
905  *    the key and counter are returned.  If the key's type is
906  *    SKBAG_KEY_ANY, 'key' is filled with an SKBAG_KEY_IPADDR for a
907  *    bag containing IPv6 addresses and an SKBAG_KEY_U32 otherwise.
908  *    'counter' is always filled with an SKBAG_COUNTER_U64.
909  *
910  *    If the range of keys does not fit into the specified type of
911  *    'key', the iterator returns SKBAG_ERR_KEY_NOT_FOUND once all
912  *    values that fit into 'key' have been visited.  When
913  *    iterating over a Bag that contains IPv6 data and the key type is
914  *    an integer, addresses in the ::ffff:0:0/96 block are
915  *    converted to IPv4 addresses, and then those addresses are
916  *    converted to native integers and returned by this function.  All
917  *    other IPv6 addresses are ignored.
918  *
919  *    If the iterator has visited all entries, the 'key' and 'counter'
920  *    values are unchanged and the function returns
921  *    SKBAG_ERR_KEY_NOT_FOUND.  The function returns SKBAG_ERR_INPUT
922  *    if any of the input parameters are NULL or if the type field of
923  *    'key' or 'counter' is not recognized.  Return SKBAG_ERR_MODIFIED
924  *    if the Bag's key size has changed; when this happens, the
925  *    iterator must be reset or destroyed.
926  */
927 skBagErr_t
928 skBagIteratorNextTyped(
929     skBagIterator_t        *iter,
930     skBagTypedKey_t        *key,
931     skBagTypedCounter_t    *counter);
932 
933 
934 /**
935  *    Reset the iterator at 'iter' so the next call to
936  *    skBagIteratorNextTyped() returns the counter associated with
937  *    the first key.
938  */
939 skBagErr_t
940 skBagIteratorReset(
941     skBagIterator_t    *iter);
942 
943 
944 /**
945  *    Return the number octets the key of 'bag' occupies for the
946  *    in-core representation of 'bag'.
947  */
948 size_t
949 skBagKeyFieldLength(
950     const skBag_t      *bag);
951 
952 
953 /**
954  *    Return the type of key that 'bag' contains, and, if 'buf' is not
955  *    NULL, fill 'buf' with a string representation of that type.  The
956  *    caller must specify the size of 'buf' in 'buflen'.  If 'buf' is
957  *    too small to hold the string representation, 'buf' is filled
958  *    with as much of the name as possible.
959  *
960  *    See also skBagKeyFieldType(), skBagCounterFieldName(), and
961  *    skBagCounterFieldType().
962  */
963 skBagFieldType_t
964 skBagKeyFieldName(
965     const skBag_t      *bag,
966     char               *buf,
967     size_t              buflen);
968 
969 
970 /**
971  *    Return the type of key that 'bag' contains.
972  *
973  *    See also skBagKeyFieldName(), skBagCounterFieldType(), and
974  *    skBagCounterFieldName().
975  */
976 skBagFieldType_t
977 skBagKeyFieldType(
978     const skBag_t      *bag);
979 
980 
981 /**
982  *    Remove 'key' from the bag 'bag'.  Return SKBAG_OK on success.
983  *    Return SKBAG_OK if 'key' is not in 'bag'.
984  */
985 #define skBagKeyRemove(rm_bag, rm_key)                          \
986     skBagCounterSet((rm_bag), (rm_key), skbag_counter_zero)
987 
988 
989 /**
990  *    Read a serialized Bag from the file specified by 'filename' into
991  *    a newly created bag and set the referent of 'bag' to its
992  *    location.  This function is a wrapper around skBagRead().
993  *
994  *    Return SKBAG_OK on success.  Return SKBAG_ERR_INPUT and do not
995  *    create the bag if any input parameter is NULL.  Return
996  *    SKBAG_ERR_READ, print an error, and do not create the bag if
997  *    'filename' cannot be opened.  Otherwise, return the error code
998  *    specified by skBagRead().
999  */
1000 skBagErr_t
1001 skBagLoad(
1002     skBag_t           **bag,
1003     const char         *filename);
1004 
1005 
1006 /**
1007  *    Modify the type or length of the key or counter for the existing
1008  *    bag 'bag'.
1009  *
1010  *    When 'key_octets' and/or 'counter_octets' is
1011  *    SKBAG_OCTETS_NO_CHANGE, the size of the key and/or counter is
1012  *    not modified.  Otherwise, the 'key_octets' and/or
1013  *    'counter_octets' values are handled as they are in
1014  *    skBagCreateTyped().
1015  *
1016  *    When 'key_octets' and/or 'counter_octets' specifies a size
1017  *    smaller than that bag's current key/counter lengths,
1018  *    keys/counters whose value is outside the range of the new
1019  *    key/counter are removed from the bag.
1020  *
1021  *    Return SKBAG_OK on success.  Return SKBAG_ERR_INPUT when 'bag'
1022  *    is NULL or when the other parameters are not recognized or have
1023  *    illegal values.
1024  *
1025  */
1026 skBagErr_t
1027 skBagModify(
1028     skBag_t            *bag,
1029     skBagFieldType_t    key_type,
1030     skBagFieldType_t    counter_type,
1031     size_t              key_octets,
1032     size_t              counter_octets);
1033 
1034 
1035 /**
1036  *    Print to the stream 'stream' meta-data on how the bag 'bag' is
1037  *    performing.
1038  */
1039 skBagErr_t
1040 skBagPrintTreeStats(
1041     const skBag_t      *bag,
1042     skstream_t         *stream_out);
1043 
1044 
1045 /**
1046  *    Read a Bag from the 'stream'.  For each key/counter pair in the
1047  *    Bag, the function invokes the callback function 'cb_entry_func'
1048  *    with the key, the counter, and the 'cb_data'.  Processing
1049  *    continues until the stream is exhausted or until 'cb_entry_func'
1050  *    returns a value other than 'SKBAG_OK'.
1051  *
1052  *    The 'cb_init_func' callback may be NULL.  If it is not NULL, the
1053  *    callback is invoked after the stream's header has been read and
1054  *    before processing any entries in the bag.  The callback is
1055  *    invoked with a partially constructed bag that may be used to
1056  *    determine the contents of 'stream'.  If the 'cb_init_func'
1057  *    callback returns a value other than SKBAG_OK, processing of the
1058  *    bag stops.
1059  *
1060  *    Return SKBAG_ERR_INPUT if the 'stream' or 'cb_entry_func' input
1061  *    parameters are NULL.  Return SKBAG_ERR_READ (and print an error)
1062  *    if there is an error reading 'bag' from 'stream'.  Return
1063  *    SKBAG_ERR_HEADER (and print an error) if 'stream' does not
1064  *    contain a Bag file, if the Bag file version is unsupported, or
1065  *    if the file contains key or counter types or octet lengths that
1066  *    are not supported by the library.  Otherwise, the return status
1067  *    of this function is the return status of 'cb_entry_func'.
1068  */
1069 skBagErr_t
1070 skBagProcessStreamTyped(
1071     skstream_t             *stream_in,
1072     void                   *cb_data,
1073     skBagStreamInitFunc_t   cb_init_func,
1074     skBagStreamEntryFunc_t  cb_entry_func);
1075 
1076 
1077 /**
1078  *    Read a serialized Bag from the input stream 'stream' into a
1079  *    newly created Bag and set 'bag' to its location.
1080  *
1081  *    Return SKBAG_OK on success.  Return SKBAG_ERR_INPUT and do not
1082  *    create the bag if any input parameter is NULL.  Return
1083  *    SKBAG_ERR_HEADER, print an error, and do not create the bag if
1084  *    'stream' does not contain a Bag file, if the bag file version is
1085  *    unsupported, or if the file contains key or counter types or
1086  *    octet lengths that are not supported by the library.  Return
1087  *    SKBAG_ERR_MEMORY if there is an error creating the bag or adding
1088  *    entries to it; in the latter case, the bag is returned.  Return
1089  *    SKBAG_ERR_READ (and print an error) if there is an error reading
1090  *    from 'stream'; the bag may or may not be created depending on
1091  *    when the error occurred.
1092  *
1093  *    See also skBagLoad().
1094  */
1095 skBagErr_t
1096 skBagRead(
1097     skBag_t           **bag,
1098     skstream_t         *stream_in);
1099 
1100 
1101 /**
1102  *    Serialize the Bag 'bag' to the file specified by 'filename'.
1103  *    This function is a wrapper around skBagWrite().
1104  *
1105  *    Return SKBAG_OK on success.  Return SKBAG_ERR_INPUT if any
1106  *    parameter is NULL.  Return SKBAG_ERR_OUTPUT (and print an error)
1107  *    if 'filename' cannot be opened for writing.  May also return the
1108  *    error codes specified by skBagWrite().
1109  */
1110 skBagErr_t
1111 skBagSave(
1112     const skBag_t      *bag,
1113     const char         *filename);
1114 
1115 
1116 /**
1117  *    Return a static string describing the skBagErr_t value 'code'.
1118  */
1119 const char *
1120 skBagStrerror(
1121     skBagErr_t          err_code);
1122 
1123 
1124 /**
1125  *    Serialize the bag 'bag' to the output stream 'stream'.  The
1126  *    caller may set the compression method of 'stream' before calling
1127  *    this function.
1128  *
1129  *    Return SKBAG_OK on success.  Return SKBAG_ERR_INPUT if any input
1130  *    parameter is NULL.  Return SKBAG_ERR_OUTPUT if there is an error
1131  *    writing 'bag' to 'stream'.
1132  *
1133  *    See also skBagSave().
1134  */
1135 skBagErr_t
1136 skBagWrite(
1137     const skBag_t      *bag,
1138     skstream_t         *stream_out);
1139 
1140 #ifdef __cplusplus
1141 }
1142 #endif
1143 #endif /* _SKBAG_H */
1144 
1145 /*
1146 ** Local Variables:
1147 ** mode:c
1148 ** indent-tabs-mode:nil
1149 ** c-basic-offset:4
1150 ** End:
1151 */
1152