Current listing makes possible to list sets with full content only.
The patch adds support partial listings, i.e. listing just
the existing setnames or listing set headers, without set members.
enum ipset_cmd_flags {
IPSET_FLAG_BIT_EXIST = 0,
IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST),
+ IPSET_FLAG_BIT_LIST_SETNAME = 1,
+ IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
+ IPSET_FLAG_BIT_LIST_HEADER = 2,
+ IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER),
};
/* Flags at CADT attribute level */
IPSET_ENV_RESOLVE = (1 << IPSET_ENV_BIT_RESOLVE),
IPSET_ENV_BIT_EXIST = 3,
IPSET_ENV_EXIST = (1 << IPSET_ENV_BIT_EXIST),
+ IPSET_ENV_BIT_LIST_SETNAME = 4,
+ IPSET_ENV_LIST_SETNAME = (1 << IPSET_ENV_BIT_LIST_SETNAME),
+ IPSET_ENV_BIT_LIST_HEADER = 5,
+ IPSET_ENV_LIST_HEADER = (1 << IPSET_ENV_BIT_LIST_HEADER),
};
extern int ipset_envopt_parse(struct ipset_session *session,
enum ipset_cmd_flags {
IPSET_FLAG_BIT_EXIST = 0,
IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST),
+ IPSET_FLAG_BIT_LIST_SETNAME = 1,
+ IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
+ IPSET_FLAG_BIT_LIST_HEADER = 2,
+ IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER),
};
/* Flags at CADT attribute level */
/* List/save set data */
-#define DUMP_INIT 0L
-#define DUMP_ALL 1L
-#define DUMP_ONE 2L
-#define DUMP_LAST 3L
+#define DUMP_INIT 0
+#define DUMP_ALL 1
+#define DUMP_ONE 2
+#define DUMP_LAST 3
+
+#define DUMP_TYPE(arg) (((u32)(arg)) & 0x0000FFFF)
+#define DUMP_FLAGS(arg) (((u32)(arg)) >> 16)
static int
ip_set_dump_done(struct netlink_callback *cb)
int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
struct nlattr *cda[IPSET_ATTR_CMD_MAX+1];
struct nlattr *attr = (void *)nlh + min_len;
+ u32 dump_type;
ip_set_id_t index;
/* Second pass, so parser can't fail */
* [..]: type specific
*/
- if (!cda[IPSET_ATTR_SETNAME]) {
- cb->args[0] = DUMP_ALL;
- return 0;
- }
+ if (cda[IPSET_ATTR_SETNAME]) {
+ index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME]));
+ if (index == IPSET_INVALID_ID)
+ return -ENOENT;
- index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME]));
- if (index == IPSET_INVALID_ID)
- return -ENOENT;
+ dump_type = DUMP_ONE;
+ cb->args[1] = index;
+ } else
+ dump_type = DUMP_ALL;
+
+ if (cda[IPSET_ATTR_FLAGS]) {
+ u32 f = ip_set_get_h32(cda[IPSET_ATTR_FLAGS]);
+ dump_type |= (f << 16);
+ }
+ cb->args[0] = dump_type;
- cb->args[0] = DUMP_ONE;
- cb->args[1] = index;
return 0;
}
struct ip_set *set = NULL;
struct nlmsghdr *nlh = NULL;
unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0;
+ u32 dump_type, dump_flags;
int ret = 0;
- if (cb->args[0] == DUMP_INIT) {
+ if (!cb->args[0]) {
ret = dump_init(cb);
if (ret < 0) {
nlh = nlmsg_hdr(cb->skb);
if (cb->args[1] >= ip_set_max)
goto out;
- max = cb->args[0] == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
+ dump_type = DUMP_TYPE(cb->args[0]);
+ dump_flags = DUMP_FLAGS(cb->args[0]);
+ max = dump_type == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
dump_last:
- pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]);
+ pr_debug("args[0]: %u %u args[1]: %ld\n",
+ dump_type, dump_flags, cb->args[1]);
for (; cb->args[1] < max; cb->args[1]++) {
index = (ip_set_id_t) cb->args[1];
set = ip_set_list[index];
if (set == NULL) {
- if (cb->args[0] == DUMP_ONE) {
+ if (dump_type == DUMP_ONE) {
ret = -ENOENT;
goto out;
}
/* When dumping all sets, we must dump "sorted"
* so that lists (unions of sets) are dumped last.
*/
- if (cb->args[0] != DUMP_ONE &&
- ((cb->args[0] == DUMP_ALL) ==
+ if (dump_type != DUMP_ONE &&
+ ((dump_type == DUMP_ALL) ==
!!(set->type->features & IPSET_DUMP_LAST)))
continue;
pr_debug("List set: %s\n", set->name);
}
NLA_PUT_U8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
NLA_PUT_STRING(skb, IPSET_ATTR_SETNAME, set->name);
+ if (dump_flags & IPSET_FLAG_LIST_SETNAME)
+ goto next_set;
switch (cb->args[2]) {
case 0:
/* Core header data */
ret = set->variant->head(set, skb);
if (ret < 0)
goto release_refcount;
+ if (dump_flags & IPSET_FLAG_LIST_HEADER)
+ goto next_set;
/* Fall through and add elements */
default:
read_lock_bh(&set->lock);
ret = set->variant->list(set, skb, cb);
read_unlock_bh(&set->lock);
- if (!cb->args[2]) {
+ if (!cb->args[2])
/* Set is done, proceed with next one */
- if (cb->args[0] == DUMP_ONE)
- cb->args[1] = IPSET_INVALID_ID;
- else
- cb->args[1]++;
- }
+ goto next_set;
goto release_refcount;
}
}
/* If we dump all sets, continue with dumping last ones */
- if (cb->args[0] == DUMP_ALL) {
- cb->args[0] = DUMP_LAST;
+ if (dump_type == DUMP_ALL) {
+ dump_type = DUMP_LAST;
+ cb->args[0] = dump_type | (dump_flags << 16);
cb->args[1] = 0;
goto dump_last;
}
nla_put_failure:
ret = -EFAULT;
+next_set:
+ if (dump_type == DUMP_ONE)
+ cb->args[1] = IPSET_INVALID_ID;
+ else
+ cb->args[1]++;
release_refcount:
/* If there was an error or set is done, release set */
if (ret || !cb->args[2]) {
case IPSET_ENV_QUIET:
case IPSET_ENV_RESOLVE:
case IPSET_ENV_EXIST:
+ case IPSET_ENV_LIST_SETNAME:
+ case IPSET_ENV_LIST_HEADER:
session->envopts |= opt;
return 0;
default:
safe_dprintf(session, ipset_print_number, IPSET_OPT_MEMSIZE);
safe_snprintf(session, "\nReferences: ");
safe_dprintf(session, ipset_print_number, IPSET_OPT_REFERENCES);
- safe_snprintf(session, "\nMembers:\n");
+ safe_snprintf(session,
+ session->envopts & IPSET_ENV_LIST_HEADER ?
+ "\n" : "\nMembers:\n");
break;
case IPSET_LIST_XML:
safe_snprintf(session, "</elements>\n <memsize>");
ATTR2DATA(session, nla, IPSET_ATTR_SETNAME, cmd_attrs);
D("setname %s", ipset_data_setname(data));
+ if (session->envopts & IPSET_ENV_LIST_SETNAME) {
+ if (session->mode == IPSET_LIST_XML)
+ safe_snprintf(session, "<ipset name=\"%s\"/>\n",
+ ipset_data_setname(data));
+ else
+ safe_snprintf(session, "%s\n",
+ ipset_data_setname(data));
+ return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_OK;
+ }
+
if (STREQ(ipset_data_setname(data), session->saved_setname)) {
/* Header part already seen */
if (ipset_data_test(data, IPSET_OPT_TYPE)
}
case IPSET_CMD_DESTROY:
case IPSET_CMD_FLUSH:
- case IPSET_CMD_LIST:
case IPSET_CMD_SAVE:
if (ipset_data_test(data, IPSET_SETNAME))
ADDATTR_SETNAME(session, nlh, data);
break;
+ case IPSET_CMD_LIST: {
+ uint32_t flags = 0;
+
+ if (session->envopts & IPSET_ENV_LIST_SETNAME)
+ flags |= IPSET_FLAG_LIST_SETNAME;
+ if (session->envopts & IPSET_ENV_LIST_HEADER)
+ flags |= IPSET_FLAG_LIST_HEADER;
+ if (ipset_data_test(data, IPSET_SETNAME))
+ ADDATTR_SETNAME(session, nlh, data);
+ if (flags) {
+ ipset_data_set(data, IPSET_OPT_FLAGS, &flags);
+ ADDATTR(session, nlh, data, IPSET_ATTR_FLAGS, AF_INET,
+ cmd_attrs);
+ }
+ break;
+ }
case IPSET_CMD_RENAME:
case IPSET_CMD_SWAP:
if (!ipset_data_test(data, IPSET_SETNAME))
.PP
COMMANDS := { \fBcreate\fR | \fBadd\fR | \fBdel\fR | \fBtest\fR | \fBdestroy\fR | \fBlist\fR | \fBsave\fR | \fBrestore\fR | \fBflush\fR | \fBrename\fR | \fBswap\fR | \fBhelp\fR | \fBversion\fR | \fB\-\fR }
.PP
-\fIOPTIONS\fR := { \fB\-exist\fR | \fB\-output\fR { \fBplain\fR | \fBsave\fR | \fBxml\fR } | \fB\-quiet\fR | \fB\-resolve\fR | \fB\-sorted\fR }
+\fIOPTIONS\fR := { \fB\-exist\fR | \fB\-output\fR { \fBplain\fR | \fBsave\fR | \fBxml\fR } | \fB\-quiet\fR | \fB\-resolve\fR | \fB\-sorted\fR | \fB\-name\fR | \fB\-terse\fR }
.PP
\fBipset\fR \fBcreate\fR \fISETNAME\fR \fITYPENAME\fR [ \fICREATE\-OPTIONS\fR ]
.PP
If the set has got reference(s), nothing is done and no set destroyed.
.TP
-\fBlist\fP [ \fISETNAME\fP ]
+\fBlist\fP [ \fISETNAME\fP ] [ \fIOPTIONS\fP ]
List the header data and the entries for the specified set, or for
all sets if none is given. The
\fB\-resolve\fP
\fB\-output\fR
can be used to control the format of the listing:
\fBplain\fR, \fBsave\fR or \fBxml\fR.
-The default is
-\fBplain\fR.
+(The default is
+\fBplain\fR.)
+If the option
+\fB\-name\fR
+is specified, just the names of the existing sets are listed. If the option
+\fB\-terse\fR
+is specified, just the set names and headers are listed.
.TP
\fBsave\fP [ \fISETNAME\fP ]
Save the given set, or all sets if none is given
.TP
\fB\-s\fP, \fB\-sorted\fP
Sorted output. When listing sets entries are listed sorted. Not supported yet.
+.TP
+\fB\-n\fP, \fB\-name\fP
+List just the names of the existing sets, i.e. suppress listing of set headers and members.
+.TP
+\fB\-t\fP, \fB\-terse\fP
+List the set names and headers, i.e. suppress listing of set members.
+
.SH "SET TYPES"
A set type comprises of the storage method by which the data is stored and
the data type(s) which are stored in the set. Therefore the
" when adding already existing elements\n"
" or when deleting non-existing elements.",
},
+ { .name = { "-n", "-name" },
+ .parse = ipset_envopt_parse,
+ .has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_LIST_SETNAME,
+ .help = "\n"
+ " When listing, list just setnames from kernel.\n",
+ },
+ { .name = { "-t", "-terse" },
+ .parse = ipset_envopt_parse,
+ .has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_LIST_HEADER,
+ .help = "\n"
+ " When listing, list setnames and set headers\n"
+ " from kernel only.",
+ },
{ },
};