git: d9ab89993138 - main - pf: migrate DIOCGETLIMIT/DIOCSETLIMIT to netlink
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 07 Jun 2024 19:14:37 UTC
The branch main has been updated by kp:
URL: https://cgit.FreeBSD.org/src/commit/?id=d9ab8999313845e87c67532437a0441d9cd57e72
commit d9ab8999313845e87c67532437a0441d9cd57e72
Author: Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2024-06-07 01:08:50 +0000
Commit: Kristof Provost <kp@FreeBSD.org>
CommitDate: 2024-06-07 18:59:02 +0000
pf: migrate DIOCGETLIMIT/DIOCSETLIMIT to netlink
Event: Kitchener-Waterloo Hackathon 202406
---
lib/libpfctl/libpfctl.c | 88 +++++++++++++++++++++++++++++--
lib/libpfctl/libpfctl.h | 2 +
sbin/pfctl/parse.y | 2 +-
sbin/pfctl/pfctl.c | 19 +++----
sbin/pfctl/pfctl_parser.h | 2 +-
sys/net/pfvar.h | 2 +
sys/netpfil/pf/pf_ioctl.c | 56 +++++++++++++-------
sys/netpfil/pf/pf_nl.c | 76 ++++++++++++++++++++++++++
sys/netpfil/pf/pf_nl.h | 8 +++
tests/sys/netpfil/pf/Makefile | 1 +
tests/sys/netpfil/pf/limits.sh | 66 +++++++++++++++++++++++
usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c | 14 +++--
12 files changed, 291 insertions(+), 45 deletions(-)
diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index a31fe6f0aff4..ebe52e7a415f 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -2213,7 +2213,7 @@ pfctl_clear_eth_rules(int dev, const char *anchorname)
}
static int
-pfctl_get_limit(int dev, const int index, uint *limit)
+_pfctl_get_limit(int dev, const int index, uint *limit)
{
struct pfioc_limit pl;
@@ -2237,7 +2237,7 @@ pfctl_set_syncookies(int dev, const struct pfctl_syncookies *s)
uint state_limit;
uint64_t lim, hi, lo;
- ret = pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit);
+ ret = _pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit);
if (ret != 0)
return (ret);
@@ -2274,7 +2274,7 @@ pfctl_get_syncookies(int dev, struct pfctl_syncookies *s)
uint state_limit;
bool enabled, adaptive;
- ret = pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit);
+ ret = _pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit);
if (ret != 0)
return (ret);
@@ -2606,3 +2606,85 @@ pfctl_get_timeout(struct pfctl_handle *h, uint32_t timeout, uint32_t *seconds)
return (e.error);
}
+int
+pfctl_set_limit(struct pfctl_handle *h, const int index, const uint limit)
+{
+ struct snl_writer nw;
+ struct snl_errmsg_data e = {};
+ struct nlmsghdr *hdr;
+ uint32_t seq_id;
+ int family_id;
+
+ family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
+ if (family_id == 0)
+ return (ENOTSUP);
+
+ snl_init_writer(&h->ss, &nw);
+ hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_SET_LIMIT);
+
+ snl_add_msg_attr_u32(&nw, PF_LI_INDEX, index);
+ snl_add_msg_attr_u32(&nw, PF_LI_LIMIT, limit);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL)
+ return (ENXIO);
+
+ seq_id = hdr->nlmsg_seq;
+
+ if (! snl_send_message(&h->ss, hdr))
+ return (ENXIO);
+
+ while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
+ }
+
+ return (e.error);
+}
+
+struct pfctl_nl_limit {
+ unsigned int limit;
+};
+#define _OUT(_field) offsetof(struct pfctl_nl_limit, _field)
+static struct snl_attr_parser ap_get_limit[] = {
+ { .type = PF_LI_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
+};
+static struct snl_field_parser fp_get_limit[] = {};
+#undef _OUT
+SNL_DECLARE_PARSER(get_limit_parser, struct genlmsghdr, fp_get_limit, ap_get_limit);
+
+int
+pfctl_get_limit(struct pfctl_handle *h, const int index, uint *limit)
+{
+ struct snl_writer nw;
+ struct pfctl_nl_limit li = {};
+ struct snl_errmsg_data e = {};
+ struct nlmsghdr *hdr;
+ uint32_t seq_id;
+ int family_id;
+
+ family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
+ if (family_id == 0)
+ return (ENOTSUP);
+
+ snl_init_writer(&h->ss, &nw);
+ hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GET_LIMIT);
+ hdr->nlmsg_flags |= NLM_F_DUMP;
+
+ snl_add_msg_attr_u32(&nw, PF_LI_INDEX, index);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL)
+ return (ENXIO);
+
+ seq_id = hdr->nlmsg_seq;
+
+ if (! snl_send_message(&h->ss, hdr))
+ return (ENXIO);
+
+ while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
+ if (! snl_parse_nlmsg(&h->ss, hdr, &get_limit_parser, &li))
+ continue;
+ }
+
+ if (limit != NULL)
+ *limit = li.limit;
+
+ return (e.error);
+}
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
index 6d59d66a924a..44c7fa47e88d 100644
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -495,5 +495,7 @@ int pfctl_natlook(struct pfctl_handle *h,
int pfctl_set_debug(struct pfctl_handle *h, uint32_t level);
int pfctl_set_timeout(struct pfctl_handle *h, uint32_t timeout, uint32_t seconds);
int pfctl_get_timeout(struct pfctl_handle *h, uint32_t timeout, uint32_t *seconds);
+int pfctl_set_limit(struct pfctl_handle *h, const int index, const uint limit);
+int pfctl_get_limit(struct pfctl_handle *h, const int index, uint *limit);
#endif
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 2876eb6e89dc..d07a3fdc188e 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -5198,7 +5198,7 @@ limit_spec : STRING NUMBER
yyerror("only positive values permitted");
YYERROR;
}
- if (pfctl_set_limit(pf, $1, $2) != 0) {
+ if (pfctl_apply_limit(pf, $1, $2) != 0) {
yyerror("unable to set limit %s %u", $1, $2);
free($1);
YYERROR;
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index d97043fc5c66..ec718f6b0a99 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -1679,21 +1679,19 @@ pfctl_show_timeouts(int dev, int opts)
int
pfctl_show_limits(int dev, int opts)
{
- struct pfioc_limit pl;
+ unsigned int limit;
int i;
if (opts & PF_OPT_SHOWALL)
pfctl_print_title("LIMITS:");
- memset(&pl, 0, sizeof(pl));
for (i = 0; pf_limits[i].name; i++) {
- pl.index = pf_limits[i].index;
- if (ioctl(dev, DIOCGETLIMIT, &pl))
+ if (pfctl_get_limit(pfh, pf_limits[i].index, &limit))
err(1, "DIOCGETLIMIT");
printf("%-13s ", pf_limits[i].name);
- if (pl.limit == UINT_MAX)
+ if (limit == UINT_MAX)
printf("unlimited\n");
else
- printf("hard limit %8u\n", pl.limit);
+ printf("hard limit %8u\n", limit);
}
return (0);
}
@@ -2425,7 +2423,7 @@ pfctl_load_options(struct pfctl *pf)
}
int
-pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
+pfctl_apply_limit(struct pfctl *pf, const char *opt, unsigned int limit)
{
int i;
@@ -2451,12 +2449,7 @@ pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
int
pfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit)
{
- struct pfioc_limit pl;
-
- memset(&pl, 0, sizeof(pl));
- pl.index = index;
- pl.limit = limit;
- if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) {
+ if (pfctl_set_limit(pf->h, index, limit)) {
if (errno == EBUSY)
warnx("Current pool size exceeds requested hard limit");
else
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index 06ab5d052631..6de998b34e52 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -288,7 +288,7 @@ void pfctl_clear_pool(struct pfctl_pool *);
int pfctl_apply_timeout(struct pfctl *, const char *, int, int);
int pfctl_set_reassembly(struct pfctl *, int, int);
int pfctl_set_optimization(struct pfctl *, const char *);
-int pfctl_set_limit(struct pfctl *, const char *, unsigned int);
+int pfctl_apply_limit(struct pfctl *, const char *, unsigned int);
int pfctl_set_logif(struct pfctl *, char *);
int pfctl_set_hostid(struct pfctl *, u_int32_t);
int pfctl_do_set_debug(struct pfctl *, char *);
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 16d3d90f4862..eb36c0aee4d1 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -2505,6 +2505,8 @@ int pf_ioctl_addrule(struct pf_krule *, uint32_t,
void pf_ioctl_clear_status(void);
int pf_ioctl_get_timeout(int, int *);
int pf_ioctl_set_timeout(int, int, int *);
+int pf_ioctl_get_limit(int, unsigned int *);
+int pf_ioctl_set_limit(int, unsigned int, unsigned int *);
void pf_krule_free(struct pf_krule *);
void pf_krule_clear_counters(struct pf_krule *);
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index cef50c00283b..af3f914982ec 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -2483,6 +2483,40 @@ pf_ioctl_get_timeout(int timeout, int *seconds)
return (0);
}
+int
+pf_ioctl_set_limit(int index, unsigned int limit, unsigned int *old_limit)
+{
+
+ PF_RULES_WLOCK();
+ if (index < 0 || index >= PF_LIMIT_MAX ||
+ V_pf_limits[index].zone == NULL) {
+ PF_RULES_WUNLOCK();
+ return (EINVAL);
+ }
+ uma_zone_set_max(V_pf_limits[index].zone, limit);
+ if (old_limit != NULL)
+ *old_limit = V_pf_limits[index].limit;
+ V_pf_limits[index].limit = limit;
+ PF_RULES_WUNLOCK();
+
+ return (0);
+}
+
+int
+pf_ioctl_get_limit(int index, unsigned int *limit)
+{
+ PF_RULES_RLOCK_TRACKER;
+
+ if (index < 0 || index >= PF_LIMIT_MAX)
+ return (EINVAL);
+
+ PF_RULES_RLOCK();
+ *limit = V_pf_limits[index].limit;
+ PF_RULES_RUNLOCK();
+
+ return (0);
+}
+
static int
pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
{
@@ -3894,32 +3928,16 @@ DIOCGETSTATESV2_full:
case DIOCGETLIMIT: {
struct pfioc_limit *pl = (struct pfioc_limit *)addr;
- if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
- error = EINVAL;
- break;
- }
- PF_RULES_RLOCK();
- pl->limit = V_pf_limits[pl->index].limit;
- PF_RULES_RUNLOCK();
+ error = pf_ioctl_get_limit(pl->index, &pl->limit);
break;
}
case DIOCSETLIMIT: {
struct pfioc_limit *pl = (struct pfioc_limit *)addr;
- int old_limit;
+ unsigned int old_limit;
- PF_RULES_WLOCK();
- if (pl->index < 0 || pl->index >= PF_LIMIT_MAX ||
- V_pf_limits[pl->index].zone == NULL) {
- PF_RULES_WUNLOCK();
- error = EINVAL;
- break;
- }
- uma_zone_set_max(V_pf_limits[pl->index].zone, pl->limit);
- old_limit = V_pf_limits[pl->index].limit;
- V_pf_limits[pl->index].limit = pl->limit;
+ error = pf_ioctl_set_limit(pl->index, pl->limit, &old_limit);
pl->limit = old_limit;
- PF_RULES_WUNLOCK();
break;
}
diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c
index 026f8caab535..57b1a4a6b5b3 100644
--- a/sys/netpfil/pf/pf_nl.c
+++ b/sys/netpfil/pf/pf_nl.c
@@ -1410,6 +1410,67 @@ pf_handle_get_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt)
return (0);
}
+struct pf_nl_set_limit
+{
+ uint32_t index;
+ uint32_t limit;
+};
+#define _OUT(_field) offsetof(struct pf_nl_set_limit, _field)
+static const struct nlattr_parser nla_p_set_limit[] = {
+ { .type = PF_LI_INDEX, .off = _OUT(index), .cb = nlattr_get_uint32 },
+ { .type = PF_LI_LIMIT, .off = _OUT(limit), .cb = nlattr_get_uint32 },
+};
+static const struct nlfield_parser nlf_p_set_limit[] = {};
+#undef _OUT
+NL_DECLARE_PARSER(set_limit_parser, struct genlmsghdr, nlf_p_set_limit, nla_p_set_limit);
+
+static int
+pf_handle_set_limit(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pf_nl_set_limit attrs = {};
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &set_limit_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ return (pf_ioctl_set_limit(attrs.index, attrs.limit, NULL));
+}
+
+static int
+pf_handle_get_limit(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pf_nl_set_limit attrs = {};
+ struct nl_writer *nw = npt->nw;
+ struct genlmsghdr *ghdr_new;
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &set_limit_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ error = pf_ioctl_get_limit(attrs.index, &attrs.limit);
+ if (error != 0)
+ return (error);
+
+ if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
+ return (ENOMEM);
+
+ ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
+ ghdr_new->cmd = PFNL_CMD_GET_LIMIT;
+ ghdr_new->version = 0;
+ ghdr_new->reserved = 0;
+
+ nlattr_add_u32(nw, PF_LI_LIMIT, attrs.limit);
+
+ if (!nlmsg_end(nw)) {
+ nlmsg_abort(nw);
+ return (ENOMEM);
+ }
+
+ return (0);
+}
+
static const struct nlhdr_parser *all_parsers[] = {
&state_parser,
&addrule_parser,
@@ -1419,6 +1480,7 @@ static const struct nlhdr_parser *all_parsers[] = {
&natlook_parser,
&set_debug_parser,
&set_timeout_parser,
+ &set_limit_parser,
};
static int family_id;
@@ -1536,6 +1598,20 @@ static const struct genl_cmd pf_cmds[] = {
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
.cmd_priv = PRIV_NETINET_PF,
},
+ {
+ .cmd_num = PFNL_CMD_SET_LIMIT,
+ .cmd_name = "SET_LIMIT",
+ .cmd_cb = pf_handle_set_limit,
+ .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_GET_LIMIT,
+ .cmd_name = "GET_LIMIT",
+ .cmd_cb = pf_handle_get_limit,
+ .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
};
void
diff --git a/sys/netpfil/pf/pf_nl.h b/sys/netpfil/pf/pf_nl.h
index 5f9d8166ca50..437cc6482dbb 100644
--- a/sys/netpfil/pf/pf_nl.h
+++ b/sys/netpfil/pf/pf_nl.h
@@ -52,6 +52,8 @@ enum {
PFNL_CMD_SET_DEBUG = 14,
PFNL_CMD_SET_TIMEOUT = 15,
PFNL_CMD_GET_TIMEOUT = 16,
+ PFNL_CMD_SET_LIMIT = 17,
+ PFNL_CMD_GET_LIMIT = 18,
__PFNL_CMD_MAX,
};
#define PFNL_CMD_MAX (__PFNL_CMD_MAX -1)
@@ -342,6 +344,12 @@ enum pf_timeout_types_t {
PF_TO_SECONDS = 2, /* u32 */
};
+enum pf_limit_types_t {
+ PF_LI_UNSPEC,
+ PF_LI_INDEX = 1, /* u32 */
+ PF_LI_LIMIT = 2, /* u32 */
+};
+
#ifdef _KERNEL
void pf_nl_register(void);
diff --git a/tests/sys/netpfil/pf/Makefile b/tests/sys/netpfil/pf/Makefile
index 089db2f19766..2840dc92f2fa 100644
--- a/tests/sys/netpfil/pf/Makefile
+++ b/tests/sys/netpfil/pf/Makefile
@@ -17,6 +17,7 @@ ATF_TESTS_SH+= altq \
fragmentation_no_reassembly \
get_state \
icmp \
+ limits \
loginterface \
killstate \
macro \
diff --git a/tests/sys/netpfil/pf/limits.sh b/tests/sys/netpfil/pf/limits.sh
new file mode 100644
index 000000000000..474684bef660
--- /dev/null
+++ b/tests/sys/netpfil/pf/limits.sh
@@ -0,0 +1,66 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2024 Kristof Provost <kp@FreeBSD.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+. $(atf_get_srcdir)/utils.subr
+
+atf_test_case "basic" "cleanup"
+basic_head()
+{
+ atf_set descr 'Test setting and retrieving limits'
+ atf_set require.user root
+}
+
+basic_body()
+{
+ pft_init
+
+ vnet_mkjail alcatraz
+
+ pft_set_rules alcatraz \
+ "set limit states 200" \
+ "set limit frags 100" \
+ "set limit src-nodes 50" \
+ "set limit table-entries 25"
+
+ atf_check -s exit:0 -o match:'states.*200' \
+ jexec alcatraz pfctl -sm
+ atf_check -s exit:0 -o match:'frags.*100' \
+ jexec alcatraz pfctl -sm
+ atf_check -s exit:0 -o match:'src-nodes.*50' \
+ jexec alcatraz pfctl -sm
+ atf_check -s exit:0 -o match:'table-entries.*25' \
+ jexec alcatraz pfctl -sm
+}
+
+basic_cleanup()
+{
+ pft_cleanup
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case "basic"
+}
diff --git a/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c b/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
index f02329901f69..9f7e6d4f31cb 100644
--- a/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
+++ b/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
@@ -318,36 +318,34 @@ pf_limits(struct snmp_context __unused *ctx, struct snmp_value *val,
u_int sub, u_int __unused vindex, enum snmp_op op)
{
asn_subid_t which = val->var.subs[sub - 1];
- struct pfioc_limit pl;
+ unsigned int index, limit;
if (op == SNMP_OP_SET)
return (SNMP_ERR_NOT_WRITEABLE);
if (op == SNMP_OP_GET) {
- bzero(&pl, sizeof(struct pfioc_limit));
-
switch (which) {
case LEAF_pfLimitsStates:
- pl.index = PF_LIMIT_STATES;
+ index = PF_LIMIT_STATES;
break;
case LEAF_pfLimitsSrcNodes:
- pl.index = PF_LIMIT_SRC_NODES;
+ index = PF_LIMIT_SRC_NODES;
break;
case LEAF_pfLimitsFrags:
- pl.index = PF_LIMIT_FRAGS;
+ index = PF_LIMIT_FRAGS;
break;
default:
return (SNMP_ERR_NOSUCHNAME);
}
- if (ioctl(pfctl_fd(pfh), DIOCGETLIMIT, &pl)) {
+ if (pfctl_get_limit(pfh, index, &limit)) {
syslog(LOG_ERR, "pf_limits(): ioctl(): %s",
strerror(errno));
return (SNMP_ERR_GENERR);
}
- val->v.uint32 = pl.limit;
+ val->v.uint32 = limit;
return (SNMP_ERR_NOERROR);
}