summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--communication.c13
-rw-r--r--ebtables.838
-rw-r--r--ebtables.c212
-rw-r--r--include/ebtables_u.h3
-rw-r--r--libebtc.c53
5 files changed, 226 insertions, 93 deletions
diff --git a/communication.c b/communication.c
index e93217a..e429d15 100644
--- a/communication.c
+++ b/communication.c
@@ -358,6 +358,8 @@ void ebt_deliver_counters(struct ebt_u_replace *u_repl, int exec_style)
/* 'Normal' rule, meaning we didn't do anything to it
* So, we just copy */
*new = *old;
+ next->cnt = *new;
+ next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
/* We've used an old counter */
old++;
/* We've set a new counter */
@@ -367,7 +369,16 @@ void ebt_deliver_counters(struct ebt_u_replace *u_repl, int exec_style)
/* Don't use this old counter */
old++;
} else {
- *new = next->cnt;
+ if (cc->type == CNT_INCR) {
+ new->pcnt = old->pcnt + next->cnt_surplus.pcnt;
+ new->bcnt = old->bcnt + next->cnt_surplus.bcnt;
+ } else if (cc->type == CNT_DECR) {
+ new->pcnt = old->pcnt - next->cnt_surplus.pcnt;
+ new->bcnt = old->bcnt - next->cnt_surplus.bcnt;
+ } else
+ *new = next->cnt;
+ next->cnt = *new;
+ next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
if (cc->type == CNT_ADD)
new++;
else {
diff --git a/ebtables.8 b/ebtables.8
index 7d8671f..44c12e3 100644
--- a/ebtables.8
+++ b/ebtables.8
@@ -26,7 +26,7 @@
.SH NAME
ebtables (v.2.0.7), ebtablesd, ebtablesu \- Ethernet bridge frame table administration
.SH SYNOPSIS
-.BR "ebtables " [ -t " table ] " - [ ADI "] chain rule specification [match extensions] [watcher extensions] target"
+.BR "ebtables " [ -t " table ] " - [ ACDI "] chain rule specification [match extensions] [watcher extensions] target"
.br
.BR "ebtables " [ -t " table ] " -P " chain " ACCEPT " | " DROP " | " RETURN
.br
@@ -117,6 +117,7 @@ Example usage:
# echo "ebtablesu commit filter" >> $PIPE
.br
# echo "ebtablesu quit" >> $PIPE
+
.SS CHAINS
There are three ebtables tables with built-in chains in the
Linux kernel. These tables are used to divide functionality into
@@ -233,20 +234,41 @@ is used.
Append a rule to the end of the selected chain.
.TP
.B "-D, --delete"
-Delete the specified rule from the selected chain. There are two ways to
+Delete the specified rule or rules from the selected chain. There are two ways to
use this command. The first is by specifying an interval of rule numbers
to delete (directly after
.BR -D ).
Syntax: \fIstart_nr\fP[\fI:end_nr\fP] (use
.B -L --Ln
-to list the rules with their rule number). When \fI:end_nr\fP is omitted, all rules starting
+to list the rules with their rule number). When \fIend_nr\fP is omitted, all rules starting
from \fIstart_nr\fP are deleted. Using negative numbers is allowed, for more
details about using negative numbers, see the
.B -I
command. The second usage is by
specifying the complete rule as it would have been specified when it was added. Only
the first encountered rule that is the same as this specified rule, in other
-words the matching rule with the lowest rule number, is deleted.
+words the matching rule with the lowest (positive) rule number, is deleted.
+.TP
+.B "-C, --change-counters"
+Change the counters of the specified rule or rules from the selected chain. There are two ways to
+use this command. The first is by specifying an interval of rule numbers
+to do the changes on (directly after
+.BR -C ).
+Syntax: \fIstart_nr\fP[\fI:end_nr\fP] (use
+.B -L --Ln
+to list the rules with their rule number). The details are the same as for the
+.BR -D " command. The second usage is by"
+specifying the complete rule as it would have been specified when it was added. Only
+the counters of the first encountered rule that is the same as this specified rule, in other
+words the matching rule with the lowest (positive) rule number, are changed.
+In the first usage, the counters are specified directly after the interval specification,
+in the second usage directly after
+.BR -C .
+First the packet counter is specified, then the byte counter. If the specified counters start
+with a '+', the counter values are added to the respective current counter values.
+If the specified counters start with a '-', the counter values are decreased from the respective
+current counter values. No bounds checking is done. If the counters don't start with '+' or '-',
+the current counters are changed to the specified counters.
.TP
.B "-I, --insert"
Insert the specified rule into the selected chain at the specified rule number.
@@ -543,6 +565,14 @@ The destination MAC address. See
(above) for more details on MAC addresses. The flag
.B --dst
is an alias for this option.
+.TP
+.BR "-c, --set-counter " "\fIpcnt bcnt\fP"
+If used with
+.BR -A " or " -I ", then the packet and byte counters of the new rule will be set to
+.IR pcnt ", resp. " bcnt ".
+If used with the
+.BR -C " or " -D " commands, only rules with a packet and byte count equal to"
+.IR pcnt ", resp. " bcnt " will match."
.SS MATCH EXTENSIONS
Ebtables extensions are dynamically loaded into the userspace tool,
diff --git a/ebtables.c b/ebtables.c
index f3e8cdd..29a1801 100644
--- a/ebtables.c
+++ b/ebtables.c
@@ -33,49 +33,67 @@
#include <fcntl.h>
#include <sys/wait.h>
+#define OPT_COMMANDS (replace->flags & OPT_COMMAND || replace->flags & OPT_ZERO)
+
+#define OPT_COMMAND 0x01
+#define OPT_TABLE 0x02
+#define OPT_IN 0x04
+#define OPT_OUT 0x08
+#define OPT_JUMP 0x10
+#define OPT_PROTOCOL 0x20
+#define OPT_SOURCE 0x40
+#define OPT_DEST 0x80
+#define OPT_ZERO 0x100
+#define OPT_LOGICALIN 0x200
+#define OPT_LOGICALOUT 0x400
+#define OPT_KERNELDATA 0x800 /* This value is also defined in ebtablesd.c */
+#define OPT_COUNT 0x1000 /* This value is also defined in libebtc.c */
+#define OPT_CNT_INCR 0x2000 /* This value is also defined in libebtc.c */
+#define OPT_CNT_DECR 0x4000 /* This value is also defined in libebtc.c */
+
/* dDfault command line options. Do not mess around with the already
* assigned numbers unless you know what you are doing */
static struct option ebt_original_options[] =
{
- { "append" , required_argument, 0, 'A' },
- { "insert" , required_argument, 0, 'I' },
- { "delete" , required_argument, 0, 'D' },
- { "list" , optional_argument, 0, 'L' },
- { "Lc" , no_argument , 0, 4 },
- { "Ln" , no_argument , 0, 5 },
- { "Lx" , no_argument , 0, 6 },
- { "Lmac2" , no_argument , 0, 12 },
- { "zero" , optional_argument, 0, 'Z' },
- { "flush" , optional_argument, 0, 'F' },
- { "policy" , required_argument, 0, 'P' },
- { "in-interface" , required_argument, 0, 'i' },
- { "in-if" , required_argument, 0, 'i' },
- { "logical-in" , required_argument, 0, 2 },
- { "logical-out" , required_argument, 0, 3 },
- { "out-interface" , required_argument, 0, 'o' },
- { "out-if" , required_argument, 0, 'o' },
- { "version" , no_argument , 0, 'V' },
- { "help" , no_argument , 0, 'h' },
- { "jump" , required_argument, 0, 'j' },
- { "set-counter" , required_argument, 0, 'c' },
- { "change-counter", required_argument, 0, 'C' },
- { "proto" , required_argument, 0, 'p' },
- { "protocol" , required_argument, 0, 'p' },
- { "db" , required_argument, 0, 'b' },
- { "source" , required_argument, 0, 's' },
- { "src" , required_argument, 0, 's' },
- { "destination" , required_argument, 0, 'd' },
- { "dst" , required_argument, 0, 'd' },
- { "table" , required_argument, 0, 't' },
- { "modprobe" , required_argument, 0, 'M' },
- { "new-chain" , required_argument, 0, 'N' },
- { "rename-chain" , required_argument, 0, 'E' },
- { "delete-chain" , optional_argument, 0, 'X' },
- { "atomic-init" , no_argument , 0, 7 },
- { "atomic-commit" , no_argument , 0, 8 },
- { "atomic-file" , required_argument, 0, 9 },
- { "atomic-save" , no_argument , 0, 10 },
- { "init-table" , no_argument , 0, 11 },
+ { "append" , required_argument, 0, 'A' },
+ { "insert" , required_argument, 0, 'I' },
+ { "delete" , required_argument, 0, 'D' },
+ { "list" , optional_argument, 0, 'L' },
+ { "Lc" , no_argument , 0, 4 },
+ { "Ln" , no_argument , 0, 5 },
+ { "Lx" , no_argument , 0, 6 },
+ { "Lmac2" , no_argument , 0, 12 },
+ { "zero" , optional_argument, 0, 'Z' },
+ { "flush" , optional_argument, 0, 'F' },
+ { "policy" , required_argument, 0, 'P' },
+ { "in-interface" , required_argument, 0, 'i' },
+ { "in-if" , required_argument, 0, 'i' },
+ { "logical-in" , required_argument, 0, 2 },
+ { "logical-out" , required_argument, 0, 3 },
+ { "out-interface" , required_argument, 0, 'o' },
+ { "out-if" , required_argument, 0, 'o' },
+ { "version" , no_argument , 0, 'V' },
+ { "help" , no_argument , 0, 'h' },
+ { "jump" , required_argument, 0, 'j' },
+ { "set-counters" , required_argument, 0, 'c' },
+ { "change-counters", required_argument, 0, 'C' },
+ { "proto" , required_argument, 0, 'p' },
+ { "protocol" , required_argument, 0, 'p' },
+ { "db" , required_argument, 0, 'b' },
+ { "source" , required_argument, 0, 's' },
+ { "src" , required_argument, 0, 's' },
+ { "destination" , required_argument, 0, 'd' },
+ { "dst" , required_argument, 0, 'd' },
+ { "table" , required_argument, 0, 't' },
+ { "modprobe" , required_argument, 0, 'M' },
+ { "new-chain" , required_argument, 0, 'N' },
+ { "rename-chain" , required_argument, 0, 'E' },
+ { "delete-chain" , optional_argument, 0, 'X' },
+ { "atomic-init" , no_argument , 0, 7 },
+ { "atomic-commit" , no_argument , 0, 8 },
+ { "atomic-file" , required_argument, 0, 9 },
+ { "atomic-save" , no_argument , 0, 10 },
+ { "init-table" , no_argument , 0, 11 },
{ 0 }
};
@@ -169,7 +187,7 @@ static void print_iface(const char *iface)
#define LIST_MAC2 0x20
/* Helper function for list_rules() */
-static void list_em(struct ebt_u_entries *entries)
+static void list_em(struct ebt_u_entries *entries, struct ebt_cntchanges *cc)
{
int i, j, space = 0, digits;
struct ebt_u_entry *hlp;
@@ -301,10 +319,24 @@ static void list_em(struct ebt_u_entries *entries)
ebt_print_bug("Target '%s' not found", hlp->t->u.name);
t->print(hlp, hlp->t);
if (replace->flags & LIST_C) {
+ uint64_t pcnt = hlp->cnt.pcnt;
+ uint64_t bcnt = hlp->cnt.bcnt;
+
+ while (cc->type == CNT_DEL)
+ cc = cc->next;
+ /* This can only happen in daemon mode */
+ if (cc->type == CNT_INCR) {
+ pcnt += hlp->cnt_surplus.pcnt;
+ bcnt += hlp->cnt_surplus.bcnt;
+ } else if (cc->type == CNT_DECR) {
+ pcnt -= hlp->cnt_surplus.pcnt;
+ bcnt -= hlp->cnt_surplus.bcnt;
+ }
+ cc = cc->next;
if (replace->flags & LIST_X)
- printf("-c %llu %llu", hlp->cnt.pcnt, hlp->cnt.bcnt);
+ printf("-c %llu %llu", pcnt, bcnt);
else
- printf(", pcnt = %llu -- bcnt = %llu", hlp->cnt.pcnt, hlp->cnt.bcnt);
+ printf(", pcnt = %llu -- bcnt = %llu", pcnt, bcnt);
}
printf("\n");
hlp = hlp->next;
@@ -328,6 +360,8 @@ static void print_help()
"--append -A chain : append to chain\n"
"--delete -D chain : delete matching rule from chain\n"
"--delete -D chain rulenum : delete rule at position rulenum from chain\n"
+"--change-counters -C chain\n"
+" [rulenum] pcnt bcnt : change counters of existing rule\n"
"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
"--list -L [chain] : list the rules in a chain or in all chains\n"
"--flush -F [chain] : delete all rules in chain or in all chains\n"
@@ -349,6 +383,8 @@ static void print_help()
"--out-if -o [!] name[+] : network output interface name\n"
"--logical-in [!] name[+] : logical bridge input interface name\n"
"--logical-out [!] name[+] : logical bridge output interface name\n"
+"--set-counters -c chain\n"
+" pcnt bcnt : set the counters of the to be added rule\n"
"--modprobe -M program : try to insert modules using this program\n"
"--version -V : print package version\n\n"
"Environment variable:\n"
@@ -375,12 +411,23 @@ ATOMIC_ENV_VARIABLE " : if set <FILE> (see above) will equal its value"
/* Execute command L */
static void list_rules()
{
- int i;
+ int i, j;
+ struct ebt_cntchanges *cc = replace->counterchanges;
if (!(replace->flags & LIST_X))
printf("Bridge table: %s\n", table->name);
if (replace->selected_chain != -1) {
- list_em(ebt_to_chain(replace));
+ for (i = 0; i < replace->selected_chain; i++) {
+ if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
+ continue;
+ j = ebt_nr_to_chain(replace, i)->nentries;
+ while (j) {
+ if (cc->type != CNT_DEL)
+ j--;
+ cc = cc->next;
+ }
+ }
+ list_em(ebt_to_chain(replace), cc);
} else {
struct ebt_u_chain_list *cl = replace->udc;
@@ -403,14 +450,27 @@ static void list_rules()
i = 0;
while (1) {
if (i < NF_BR_NUMHOOKS) {
- if (replace->valid_hooks & (1 << i))
- list_em(replace->hook_entry[i]);
+ if (replace->valid_hooks & (1 << i)) {
+ list_em(replace->hook_entry[i], cc);
+ j = ebt_nr_to_chain(replace, i)->nentries;
+ while (j) {
+ if (cc->type != CNT_DEL)
+ j--;
+ cc = cc->next;
+ }
+ }
i++;
continue;
} else {
if (!cl)
break;
- list_em(cl->udc);
+ list_em(cl->udc, cc);
+ j = ebt_nr_to_chain(replace, i)->nentries;
+ while (j) {
+ if (cc->type != CNT_DEL)
+ j--;
+ cc = cc->next;
+ }
cl = cl->next;
}
}
@@ -450,7 +510,7 @@ static int parse_change_counters_rule(int argc, char **argv, int *rule_nr, int *
if (optind + 1 >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9')) ||
(argv[optind + 1][0] == '-' && (argv[optind + 1][1] < '0' && argv[optind + 1][1] > '9')))
ebt_print_error2("The command -C needs at least 3 arguments");
- if (optind + 2 < argc && (argv[optind + 2][0] != '-' || (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) {
+ if (optind + 2 < argc && (argv[optind + 2][0] != '-' || (argv[optind + 2][1] >= '0' && argv[optind + 2][1] <= '9'))) {
if (optind + 3 != argc)
ebt_print_error2("No extra options allowed with -C start_nr[:end_nr] pcnt bcnt");
if (parse_delete_rule(argv[optind], rule_nr, rule_nr_end))
@@ -458,16 +518,39 @@ static int parse_change_counters_rule(int argc, char **argv, int *rule_nr, int *
optind++;
}
- new_entry->cnt.pcnt = strtoull(argv[optind], &buffer, 10);
- if (*buffer != '\0')
- ebt_print_error2("Packet counter '%s' invalid", argv[optind])
- optind++;
- new_entry->cnt.bcnt = strtoull(argv[optind], &buffer, 10);
- if (*buffer != '\0')
- ebt_print_error2("Packet counter '%s' invalid", argv[optind])
+ if (argv[optind][0] == '+') {
+ if (argv[optind + 1][0] != '+')
+ ebt_print_error2("If one counter is increased, the other should be increased too (perhaps put a '+' before '%s')", argv[optind + 1]);
+ replace->flags |= OPT_CNT_INCR;
+ new_entry->cnt_surplus.pcnt = strtoull(argv[optind] + 1, &buffer, 10);
+ if (*buffer != '\0')
+ goto invalid;
+ optind++;
+ new_entry->cnt_surplus.bcnt = strtoull(argv[optind] + 1, &buffer, 10);
+ } else if (argv[optind][0] == '-') {
+ if (argv[optind + 1][0] != '-')
+ ebt_print_error2("If one counter is decreased, the other should be decreased too (perhaps put a '-' before '%s')", argv[optind + 1]);
+ replace->flags |= OPT_CNT_DECR;
+ new_entry->cnt_surplus.pcnt = strtoull(argv[optind] + 1, &buffer, 10);
+ if (*buffer != '\0')
+ goto invalid;
+ optind++;
+ new_entry->cnt_surplus.bcnt = strtoull(argv[optind] + 1, &buffer, 10);
+ } else {
+ if (argv[optind + 1][0] == '-' || argv[optind + 1][0] == '+')
+ ebt_print_error2("If one counter is %screased, the other should be %screased too (perhaps put a '%s' before '%s')",
+ argv[optind + 1][0] == '-' ? "de" : "in", argv[optind + 1][0] == '-' ? "de" : "in", argv[optind]);
+ new_entry->cnt_surplus.pcnt = strtoull(argv[optind], &buffer, 10);
+ optind++;
+ new_entry->cnt_surplus.bcnt = strtoull(argv[optind], &buffer, 10);
+ }
+ if (*buffer != '\0')
+ goto invalid;
optind++;
return 0;
+invalid:
+ ebt_print_error2("Packet counter '%s' invalid", argv[optind]);
}
static int parse_iface(char *iface, char *option)
@@ -492,21 +575,6 @@ void ebt_early_init_once()
ebt_iterate_targets(merge_target);
}
-#define OPT_COMMANDS (replace->flags & OPT_COMMAND || replace->flags & OPT_ZERO)
-
-#define OPT_COMMAND 0x01
-#define OPT_TABLE 0x02
-#define OPT_IN 0x04
-#define OPT_OUT 0x08
-#define OPT_JUMP 0x10
-#define OPT_PROTOCOL 0x20
-#define OPT_SOURCE 0x40
-#define OPT_DEST 0x80
-#define OPT_ZERO 0x100
-#define OPT_LOGICALIN 0x200
-#define OPT_LOGICALOUT 0x400
-#define OPT_KERNELDATA 0x800 /* This value is also defined in ebtablesd.c */
-#define OPT_COUNT 0x1000
int do_command(int argc, char *argv[], int exec_style,
struct ebt_u_replace *replace_)
{
@@ -758,7 +826,7 @@ print_zero:
case 'c': /* Set counters */
if (!OPT_COMMANDS)
ebt_print_error2("No command specified");
- if (replace->command != 'A' && replace->command != 'D' && replace->command != 'I')
+ if (replace->command != 'A' && replace->command != 'D' && replace->command != 'I' && replace->command != 'C')
ebt_print_error2("Command and option do not match");
if (c == 'i') {
ebt_check_option2(&(replace->flags), OPT_IN);
@@ -1167,7 +1235,7 @@ delete_the_rule:
if (ebt_errormsg[0] != '\0')
return -1;
} else if (replace->command == 'C') {
- ebt_change_counters(replace, new_entry, rule_nr, rule_nr_end, &(new_entry->cnt));
+ ebt_change_counters(replace, new_entry, rule_nr, rule_nr_end, &(new_entry->cnt_surplus));
if (ebt_errormsg[0] != '\0')
return -1;
}
diff --git a/include/ebtables_u.h b/include/ebtables_u.h
index 24c5045..ab08f2e 100644
--- a/include/ebtables_u.h
+++ b/include/ebtables_u.h
@@ -130,6 +130,7 @@ struct ebt_u_entry
struct ebt_entry_target *t;
struct ebt_u_entry *next;
struct ebt_counter cnt;
+ struct ebt_counter cnt_surplus; /* for increasing/decreasing a counter and for option 'C' */
/* the standard target needs this to know the name of a udc when
* printing out rules. */
struct ebt_u_replace *replace;
@@ -328,6 +329,8 @@ __ret;})
#define CNT_OWRITE 3
#define CNT_ZERO 4
#define CNT_CHANGE 5
+#define CNT_INCR 6
+#define CNT_DECR 7
extern const char *ebt_hooknames[NF_BR_NUMHOOKS];
extern const char *ebt_standard_targets[NUM_STANDARD_TARGETS];
diff --git a/libebtc.c b/libebtc.c
index a0dabde..964fa8e 100644
--- a/libebtc.c
+++ b/libebtc.c
@@ -170,7 +170,7 @@ void ebt_initialize_entry(struct ebt_u_entry *e)
e->w_list = NULL;
e->t = (struct ebt_entry_target *)ebt_find_target(EBT_STANDARD_TARGET);
ebt_find_target(EBT_STANDARD_TARGET)->used = 1;
- e->cnt.pcnt = e->cnt.bcnt = 0;
+ e->cnt.pcnt = e->cnt.bcnt = e->cnt_surplus.pcnt = e->cnt_surplus.bcnt = 0;
if (!e->t)
ebt_print_bug("Couldn't load standard target");
@@ -580,6 +580,7 @@ letscontinue:
entries->entries = NULL;
}
+#define OPT_COUNT 0x1000 /* This value is also defined in ebtables.c */
/* Returns the rule number on success (starting from 0), -1 on failure
*
* This function expects the ebt_{match,watcher,target} members of new_entry
@@ -621,6 +622,9 @@ int ebt_check_rule_exists(struct ebt_u_replace *replace,
if (new_entry->bitmask != u_e->bitmask ||
new_entry->invflags != u_e->invflags)
continue;
+ if (replace->flags & OPT_COUNT && (new_entry->cnt.pcnt !=
+ u_e->cnt.pcnt || new_entry->cnt.bcnt != u_e->cnt.bcnt))
+ continue;
/* Compare all matches */
m_l = new_entry->m_list;
j = 0;
@@ -895,6 +899,8 @@ void ebt_delete_rule(struct ebt_u_replace *replace,
}
}
+#define OPT_CNT_INCR 0x2000 /* This value is also defined in ebtables.c */
+#define OPT_CNT_DECR 0x4000 /* This value is also defined in ebtables.c */
/* Change the counters of a rule or rules
* begin == end == 0: change counters of the rule corresponding to new_entry
*
@@ -909,7 +915,6 @@ void ebt_change_counters(struct ebt_u_replace *replace,
struct ebt_u_entry *u_e;
struct ebt_u_entries *entries = ebt_to_chain(replace);
struct ebt_cntchanges *cc = replace->counterchanges;
- struct ebt_cntchanges **prev_cc = &(replace->counterchanges);
if (check_and_change_rule_number(replace, new_entry, &begin, &end))
return;
@@ -921,7 +926,6 @@ void ebt_change_counters(struct ebt_u_replace *replace,
while (j) {
if (cc->type != CNT_DEL)
j--;
- prev_cc = &(cc->next);
cc = cc->next;
}
}
@@ -929,28 +933,45 @@ void ebt_change_counters(struct ebt_u_replace *replace,
while (i) {
if (cc->type != CNT_DEL)
i--;
- prev_cc = &(cc->next);
cc = cc->next;
}
+ u_e = entries->entries;
+ for (i = 0; i < begin; i++)
+ u_e = u_e->next;
i = end - begin + 1;
while (i) {
if (cc->type != CNT_DEL) {
i--;
- /* A -C after a -A remains a -A */
- if (cc->type != CNT_ADD && cc->type != CNT_OWRITE)
- cc->type = CNT_CHANGE;
+ if (cc->type != CNT_ADD && cc->type != CNT_OWRITE) {
+ /* In daemon mode, we want to make sure we don't lose
+ * any counted packets/bytes (the kernel is still counting
+ * while we are changing things in userspace). Therefore,
+ * we need to add the amount to the counters in the kernel,
+ * not the counters copied earlier from the kernel. */
+ u_e->cnt_surplus = *cnt;
+ if (replace->flags & OPT_CNT_INCR) {
+ cc->type = CNT_INCR;
+ } else if (replace->flags & OPT_CNT_DECR)
+ cc->type = CNT_DECR;
+ else {
+ cc->type = CNT_CHANGE;
+ u_e->cnt = *cnt;
+ u_e->cnt_surplus.pcnt = u_e->cnt_surplus.bcnt = 0;
+ }
+ } else { /* A -C after a -A remains a -A */
+ if (replace->flags & OPT_CNT_INCR) {
+ u_e->cnt.pcnt += cnt->pcnt;
+ u_e->cnt.bcnt += cnt->bcnt;
+ } else if (replace->flags & OPT_CNT_DECR) {
+ u_e->cnt.pcnt -= cnt->pcnt;
+ u_e->cnt.bcnt -= cnt->bcnt;
+ } else
+ u_e->cnt = *cnt;
+ }
+ u_e = u_e->next;
}
- prev_cc = &(cc->next);
cc = cc->next;
}
- u_e = entries->entries;
- for (i = 0; i < begin; i++)
- u_e = u_e->next;
- i = end - begin + 1;
- while(i--) {
- u_e->cnt = *cnt;
- u_e = u_e->next;
- }
}
/* Selected_chain == -1 : zero all counters