Add O_EXTERNAL_DATA opcode support.

This opcode can be used to attach some data to external action opcode.
And unlike to O_EXTERNAL_INSTANCE opcode, this opcode does not require
creating of named instance to pass configuration arguments to external
action handler. The data is coming just next to O_EXTERNAL_ACTION opcode.

The userlevel part currenly supports formatting for opcode with ipfw_insn
size, by default it expects u16 numeric value in the arg1.

Obtained from:	Yandex LLC
MFC after:	2 weeks
Sponsored by:	Yandex LLC
This commit is contained in:
Andrey V. Elsukov 2017-04-03 02:44:40 +00:00
parent 399ad57874
commit 11c56650f0
4 changed files with 40 additions and 13 deletions

View File

@ -1642,6 +1642,22 @@ show_static_rule(struct cmdline_opts *co, struct format_opts *fo,
break;
}
case O_EXTERNAL_DATA: {
if (has_eaction == NULL)
break;
/*
* Currently we support data formatting only for
* external data with datalen u16. For unknown data
* print its size in bytes.
*/
if (cmd->len == F_INSN_SIZE(ipfw_insn))
bprintf(bp, " %u", cmd->arg1);
else
bprintf(bp, " %ubytes",
cmd->len * sizeof(uint32_t));
break;
}
case O_SETDSCP:
{
const char *code;

View File

@ -281,6 +281,7 @@ enum ipfw_opcodes { /* arguments (4 byte each) */
O_EXTERNAL_ACTION, /* arg1=id of external action handler */
O_EXTERNAL_INSTANCE, /* arg1=id of eaction handler instance */
O_EXTERNAL_DATA, /* variable length data */
O_LAST_OPCODE /* not an opcode! */
};

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2016 Yandex LLC
* Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
* Copyright (c) 2016-2017 Yandex LLC
* Copyright (c) 2016-2017 Andrey V. Elsukov <ae@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -57,7 +57,7 @@ __FBSDID("$FreeBSD$");
* rules.
* Module should implement opcode handler with type ipfw_eaction_t.
* This handler will be called by ipfw_chk() function when
* O_EXTERNAL_ACTION opcode will be matched. The handler must return
* O_EXTERNAL_ACTION opcode is matched. The handler must return
* value used as return value in ipfw_chk(), i.e. IP_FW_PASS,
* IP_FW_DENY (see ip_fw_private.h).
* Also the last argument must be set by handler. If it is zero,
@ -69,9 +69,12 @@ __FBSDID("$FreeBSD$");
* This function will return eaction_id, that can be used by module.
*
* It is possible to pass some additional information to external
* action handler via the O_EXTERNAL_INSTANCE opcode. This opcode
* will be next after the O_EXTERNAL_ACTION opcode. cmd->arg1 will
* contain index of named object related to instance of external action.
* action handler using O_EXTERNAL_INSTANCE and O_EXTERNAL_DATA opcodes.
* Such opcodes should be next after the O_EXTERNAL_ACTION opcode.
* For the O_EXTERNAL_INSTANCE opcode the cmd->arg1 contains index of named
* object related to an instance of external action.
* For the O_EXTERNAL_DATA opcode the cmd contains the data that can be used
* by external action handler without needing to create named instance.
*
* In case when eaction module uses named instances, it should register
* opcode rewriting routines for O_EXTERNAL_INSTANCE opcode. The
@ -284,11 +287,13 @@ reset_eaction_obj(struct ip_fw_chain *ch, uint16_t eaction_id)
/*
* Since named_object related to this instance will be
* also destroyed, truncate the chain of opcodes to
* remove O_EXTERNAL_INSTANCE opcode.
* remove the rest of cmd chain just after O_EXTERNAL_ACTION
* opcode.
*/
if (rule->act_ofs < rule->cmd_len - 1) {
EACTION_DEBUG("truncate rule %d", rule->rulenum);
rule->cmd_len--;
EACTION_DEBUG("truncate rule %d: len %u -> %u",
rule->rulenum, rule->cmd_len, rule->act_ofs + 1);
rule->cmd_len = rule->act_ofs + 1;
}
}
IPFW_WUNLOCK(ch);

View File

@ -1736,11 +1736,16 @@ check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci)
return (EINVAL);
}
ci->object_opcodes++;
/* Do we have O_EXTERNAL_INSTANCE opcode? */
/*
* Do we have O_EXTERNAL_INSTANCE or O_EXTERNAL_DATA
* opcode?
*/
if (l != cmdlen) {
l -= cmdlen;
cmd += cmdlen;
cmdlen = F_LEN(cmd);
if (cmd->opcode == O_EXTERNAL_DATA)
goto check_action;
if (cmd->opcode != O_EXTERNAL_INSTANCE) {
printf("ipfw: invalid opcode "
"next to external action %u\n",
@ -2618,11 +2623,11 @@ unref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule)
continue;
no = rw->find_bykidx(ch, kidx);
KASSERT(no != NULL, ("table id %d not found", kidx));
KASSERT(no != NULL, ("object id %d not found", kidx));
KASSERT(no->subtype == subtype,
("wrong type %d (%d) for table id %d",
("wrong type %d (%d) for object id %d",
no->subtype, subtype, kidx));
KASSERT(no->refcnt > 0, ("refcount for table %d is %d",
KASSERT(no->refcnt > 0, ("refcount for object %d is %d",
kidx, no->refcnt));
if (no->refcnt == 1 && rw->destroy_object != NULL)