diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/netlink_delinearize.c | 23 | ||||
-rw-r--r-- | src/netlink_linearize.c | 35 | ||||
-rw-r--r-- | src/payload.c | 32 | ||||
-rw-r--r-- | src/proto.c | 17 |
4 files changed, 59 insertions, 48 deletions
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 3e1f912c..e5cee163 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -998,8 +998,7 @@ static void integer_type_postprocess(struct expr *expr) static void payload_match_expand(struct rule_pp_ctx *ctx, struct expr *expr, - struct expr *payload, - struct expr *mask) + struct expr *payload) { struct expr *left = payload, *right = expr->right, *tmp; struct list_head list = LIST_HEAD_INIT(list); @@ -1008,7 +1007,7 @@ static void payload_match_expand(struct rule_pp_ctx *ctx, enum proto_bases base = left->payload.base; const struct expr_ops *payload_ops = left->ops; - payload_expr_expand(&list, left, mask, &ctx->pctx); + payload_expr_expand(&list, left, &ctx->pctx); list_for_each_entry(left, &list, list) { tmp = constant_expr_splice(right, left->len); @@ -1063,8 +1062,7 @@ static void payload_match_expand(struct rule_pp_ctx *ctx, static void payload_match_postprocess(struct rule_pp_ctx *ctx, struct expr *expr, - struct expr *payload, - struct expr *mask) + struct expr *payload) { enum proto_bases base = payload->payload.base; @@ -1075,7 +1073,7 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx, case OP_EQ: case OP_NEQ: if (expr->right->ops->type == EXPR_VALUE) { - payload_match_expand(ctx, expr, payload, mask); + payload_match_expand(ctx, expr, payload); break; } /* Fall through */ @@ -1190,6 +1188,7 @@ static void relational_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *e binop->right->ops->type == EXPR_VALUE) { struct expr *payload = binop->left; struct expr *mask = binop->right; + unsigned int shift; /* * This *might* be a payload match testing header fields that @@ -1214,7 +1213,7 @@ static void relational_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *e * payload_expr_trim will figure out if the mask is needed to match * templates. */ - if (payload_expr_trim(payload, mask, &ctx->pctx)) { + if (payload_expr_trim(payload, mask, &ctx->pctx, &shift)) { /* mask is implicit, binop needs to be removed. * * Fix all values of the expression according to the mask @@ -1226,13 +1225,11 @@ static void relational_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *e */ if (value->ops->type == EXPR_VALUE) { assert(value->len >= expr->left->right->len); - value->len = mask->len; + mpz_rshift_ui(value->value, shift); + value->len = payload->len; } - payload->len = mask->len; - payload->payload.offset += mpz_scan1(mask->value, 0); - - payload_match_postprocess(ctx, expr, payload, mask); + payload_match_postprocess(ctx, expr, payload); assert(expr->left->ops->type == EXPR_BINOP); @@ -1383,7 +1380,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) case EXPR_RELATIONAL: switch (expr->left->ops->type) { case EXPR_PAYLOAD: - payload_match_postprocess(ctx, expr, expr->left, NULL); + payload_match_postprocess(ctx, expr, expr->left); return; default: expr_postprocess(ctx, &expr->left); diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index 0790dce3..131c3f95 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -103,27 +103,37 @@ static void netlink_gen_concat(struct netlink_linearize_ctx *ctx, } } +static unsigned int payload_shift_calc(const struct expr *expr) +{ + unsigned int offset, len; + int shift; + + offset = expr->payload.offset % BITS_PER_BYTE; + len = round_up(expr->len, BITS_PER_BYTE); + shift = len - (offset + expr->len); + assert(shift >= 0); + + return shift; +} + static void netlink_gen_payload_mask(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg) { struct nft_data_linearize nld, zero = {}; + unsigned int shift, len, masklen; struct nftnl_expr *nle; - unsigned int offset, len, masklen; mpz_t mask; - offset = expr->payload.offset % BITS_PER_BYTE; - masklen = expr->len + offset; - - if (masklen > 128) - BUG("expr mask length is %u (len %u, offset %u)\n", - masklen, expr->len, offset); + shift = payload_shift_calc(expr); + if (!shift && expr->payload.offset % BITS_PER_BYTE == 0) + return; + masklen = expr->len + shift; + assert(masklen <= NFT_REG_SIZE * BITS_PER_BYTE); mpz_init2(mask, masklen); mpz_bitmask(mask, expr->len); - - if (offset) - mpz_lshift_ui(mask, offset); + mpz_lshift_ui(mask, shift); nle = alloc_nft_expr("bitwise"); @@ -158,8 +168,7 @@ static void netlink_gen_payload(struct netlink_linearize_ctx *ctx, nftnl_rule_add_expr(ctx->nlr, nle); - if (expr->len % BITS_PER_BYTE) - netlink_gen_payload_mask(ctx, expr, dreg); + netlink_gen_payload_mask(ctx, expr, dreg); } static void netlink_gen_exthdr(struct netlink_linearize_ctx *ctx, @@ -287,7 +296,7 @@ static void payload_shift_value(const struct expr *left, struct expr *right) left->ops->type != EXPR_PAYLOAD) return; - mpz_lshift_ui(right->value, left->payload.offset % BITS_PER_BYTE); + mpz_lshift_ui(right->value, payload_shift_calc(left)); } static struct expr *netlink_gen_prefix(struct netlink_linearize_ctx *ctx, diff --git a/src/payload.c b/src/payload.c index a97041e1..fe91ee0d 100644 --- a/src/payload.c +++ b/src/payload.c @@ -339,18 +339,21 @@ static unsigned int mask_length(const struct expr *mask) * Walk the template list and determine if a match can be found without * using the provided mask. * - * If the mask has to be used, trim the mask length accordingly - * and return true to let the caller know that the mask is a dependency. + * If the mask has to be used, trim the payload expression length accordingly, + * adjust the payload offset and return true to let the caller know that the + * mask can be removed. This function also returns the shift for the right hand + * constant side of the expression. */ bool payload_expr_trim(struct expr *expr, struct expr *mask, - const struct proto_ctx *ctx) + const struct proto_ctx *ctx, unsigned int *shift) { - unsigned int payload_offset = expr->payload.offset + mask_to_offset(mask); + unsigned int payload_offset = expr->payload.offset; + unsigned int mask_offset = mask_to_offset(mask); unsigned int mask_len = mask_length(mask); const struct proto_hdr_template *tmpl; unsigned int payload_len = expr->len; const struct proto_desc *desc; - unsigned int i, matched_len = mask_to_offset(mask); + unsigned int off, i, len = 0; assert(expr->ops->type == EXPR_PAYLOAD); @@ -365,6 +368,9 @@ bool payload_expr_trim(struct expr *expr, struct expr *mask, payload_offset -= ctx->protocol[expr->payload.base].offset; } + off = round_up(mask->len, BITS_PER_BYTE) - mask_len; + payload_offset += off; + for (i = 1; i < array_size(desc->templates); i++) { tmpl = &desc->templates[i]; if (tmpl->offset != payload_offset) @@ -374,14 +380,15 @@ bool payload_expr_trim(struct expr *expr, struct expr *mask, return false; payload_len -= tmpl->len; - matched_len += tmpl->len; payload_offset += tmpl->len; + len += tmpl->len; if (payload_len == 0) return false; - if (matched_len == mask_len) { - assert(mask->len >= mask_len); - mask->len = mask_len; + if (mask_offset + len == mask_len) { + expr->payload.offset += off; + expr->len = len; + *shift = mask_offset; return true; } } @@ -395,7 +402,6 @@ bool payload_expr_trim(struct expr *expr, struct expr *mask, * * @list: list to append expanded payload expressions to * @expr: the payload expression to expand - * @mask: optional/implicit mask to use when searching templates * @ctx: protocol context * * Expand a merged adjacent payload expression into its original components @@ -405,16 +411,14 @@ bool payload_expr_trim(struct expr *expr, struct expr *mask, * offset order. */ void payload_expr_expand(struct list_head *list, struct expr *expr, - struct expr *mask, const struct proto_ctx *ctx) + const struct proto_ctx *ctx) { - unsigned int off = mask_to_offset(mask); const struct proto_hdr_template *tmpl; const struct proto_desc *desc; struct expr *new; unsigned int i; assert(expr->ops->type == EXPR_PAYLOAD); - assert(!mask || mask->len != 0); desc = ctx->protocol[expr->payload.base].desc; if (desc == NULL) @@ -431,7 +435,7 @@ void payload_expr_expand(struct list_head *list, struct expr *expr, list_add_tail(&new->list, list); expr->len -= tmpl->len; expr->payload.offset += tmpl->len; - if (expr->len == off) + if (expr->len == 0) return; } else break; diff --git a/src/proto.c b/src/proto.c index 0fe0b88e..68d635f5 100644 --- a/src/proto.c +++ b/src/proto.c @@ -407,9 +407,9 @@ const struct proto_desc proto_tcp = { [TCPHDR_SEQ] = TCPHDR_FIELD("sequence", seq), [TCPHDR_ACKSEQ] = TCPHDR_FIELD("ackseq", ack_seq), [TCPHDR_DOFF] = HDR_BITFIELD("doff", &integer_type, - (12 * BITS_PER_BYTE) + 4, 4), + (12 * BITS_PER_BYTE), 4), [TCPHDR_RESERVED] = HDR_BITFIELD("reserved", &integer_type, - (12 * BITS_PER_BYTE) + 0, 4), + (12 * BITS_PER_BYTE) + 4, 4), [TCPHDR_FLAGS] = HDR_BITFIELD("flags", &tcp_flag_type, 13 * BITS_PER_BYTE, BITS_PER_BYTE), @@ -459,7 +459,8 @@ const struct proto_desc proto_dccp = { .templates = { [DCCPHDR_SPORT] = INET_SERVICE("sport", struct dccp_hdr, dccph_sport), [DCCPHDR_DPORT] = INET_SERVICE("dport", struct dccp_hdr, dccph_dport), - [DCCPHDR_TYPE] = HDR_BITFIELD("type", &dccp_pkttype_type, 67, 4), + [DCCPHDR_TYPE] = HDR_BITFIELD("type", &dccp_pkttype_type, + (8 * BITS_PER_BYTE) + 3, 4), }, }; @@ -508,8 +509,8 @@ const struct proto_desc proto_ip = { PROTO_LINK(IPPROTO_SCTP, &proto_sctp), }, .templates = { - [IPHDR_VERSION] = HDR_BITFIELD("version", &integer_type, 4, 4), - [IPHDR_HDRLENGTH] = HDR_BITFIELD("hdrlength", &integer_type, 0, 4), + [IPHDR_VERSION] = HDR_BITFIELD("version", &integer_type, 0, 4), + [IPHDR_HDRLENGTH] = HDR_BITFIELD("hdrlength", &integer_type, 4, 4), [IPHDR_TOS] = IPHDR_FIELD("tos", tos), [IPHDR_LENGTH] = IPHDR_FIELD("length", tot_len), [IPHDR_ID] = IPHDR_FIELD("id", id), @@ -730,9 +731,9 @@ const struct proto_desc proto_vlan = { }, .templates = { - [VLANHDR_VID] = VLANHDR_BITFIELD("id", 0, 12), - [VLANHDR_CFI] = VLANHDR_BITFIELD("cfi", 12, 1), - [VLANHDR_PCP] = VLANHDR_BITFIELD("pcp", 13, 3), + [VLANHDR_PCP] = VLANHDR_BITFIELD("pcp", 0, 3), + [VLANHDR_CFI] = VLANHDR_BITFIELD("cfi", 3, 1), + [VLANHDR_VID] = VLANHDR_BITFIELD("id", 4, 12), [VLANHDR_TYPE] = VLANHDR_TYPE("type", ðertype_type, vlan_type), }, }; |