/* * debug attribute TCA_EM_META_HDR */ struct tcf_meta_hdr *debug_tca_em_meta_hdr(int lev, struct rtattr *meta, const char *name) { struct tcf_meta_hdr *hdr; struct tcf_meta_val *left, *right; if(debug_rta_len_chk(lev, meta, name, sizeof(*hdr))) return(NULL); hdr = (struct tcf_meta_hdr *)RTA_DATA(meta); left = &(hdr->left); right = &(hdr->right); rec_dbg(lev, "%s(%hu):", name, RTA_ALIGN(meta->rta_len)); rec_dbg(lev, " [ tcf_meta_hdr(%d) ]", sizeof(*hdr)); rec_dbg(lev, " [ tcf_meta_val left(%d) ]", sizeof(*left)); rec_dbg(lev, " kind(%d): 0x%04x(%s,%s)", sizeof(left->kind), left->kind, conv_tcf_meta_type(TCF_META_TYPE(left->kind), 1), conv_tcf_meta_id(TCF_META_ID(left->kind), 1)); rec_dbg(lev, " shift(%d): %d", sizeof(left->shift), left->shift); rec_dbg(lev, " op(%d): %d(%s)", sizeof(left->op), left->op, conv_tcf_em_opnd(left->op, 1)); rec_dbg(lev, " [ tcf_meta_val right(%d) ]", sizeof(*right)); rec_dbg(lev, " kind(%d): 0x%04x(%s,%s)", sizeof(right->kind), right->kind, conv_tcf_meta_type(TCF_META_TYPE(right->kind), 1), conv_tcf_meta_id(TCF_META_ID(right->kind), 1)); rec_dbg(lev, " shift(%d): %d", sizeof(right->shift), right->shift); rec_dbg(lev, " op(%d): %d(%s)", sizeof(right->op), right->op, conv_tcf_em_opnd(right->op, 1)); return(hdr); }
static int meta_parse(struct rtnl_ematch *e, void *data, size_t len) { struct meta_data *m = rtnl_ematch_data(e); struct nlattr *tb[TCA_EM_META_MAX+1]; struct rtnl_meta_value *v; struct tcf_meta_hdr *hdr; void *vdata = NULL; size_t vlen = 0; int err; if ((err = nla_parse(tb, TCA_EM_META_MAX, data, len, meta_policy)) < 0) return err; if (!tb[TCA_EM_META_HDR]) return -NLE_MISSING_ATTR; hdr = nla_data(tb[TCA_EM_META_HDR]); if (tb[TCA_EM_META_LVALUE]) { vdata = nla_data(tb[TCA_EM_META_LVALUE]); vlen = nla_len(tb[TCA_EM_META_LVALUE]); } v = meta_alloc(TCF_META_TYPE(hdr->left.kind), TCF_META_ID(hdr->left.kind), hdr->left.shift, vdata, vlen); if (!v) return -NLE_NOMEM; m->left = v; vlen = 0; if (tb[TCA_EM_META_RVALUE]) { vdata = nla_data(tb[TCA_EM_META_RVALUE]); vlen = nla_len(tb[TCA_EM_META_RVALUE]); } v = meta_alloc(TCF_META_TYPE(hdr->right.kind), TCF_META_ID(hdr->right.kind), hdr->right.shift, vdata, vlen); if (!v) { rtnl_meta_value_put(m->left); return -NLE_NOMEM; } m->right = v; m->opnd = hdr->left.op; return 0; }
static inline int is_compatible(struct tcf_meta_val *what, struct tcf_meta_val *needed) { char *p; struct meta_entry *entry; entry = lookup_meta_entry_byid(TCF_META_ID(what->kind)); if (entry == NULL) return 0; for (p = entry->mask; p; p++) if (map_type(*p) == TCF_META_TYPE(needed->kind)) return 1; return 0; }
static inline void dump_value(struct nlmsghdr *n, int tlv, unsigned long val, struct tcf_meta_val *hdr) { __u32 t; switch (TCF_META_TYPE(hdr->kind)) { case TCF_META_TYPE_INT: t = val; addattr_l(n, MAX_MSG, tlv, &t, sizeof(t)); break; case TCF_META_TYPE_VAR: if (TCF_META_ID(hdr->kind) == TCF_META_ID_VALUE) { struct bstr *a = (struct bstr *) val; addattr_l(n, MAX_MSG, tlv, a->data, a->len); } break; } }
/* * debug attribute TCA_EM_META_LVALUE */ void debug_tca_em_meta_value(int lev, struct rtattr *meta, const char *name, struct tcf_meta_val *p) { int i, type, len = RTA_PAYLOAD(meta) + 1; char *data = (char *)RTA_DATA(meta), *val; type = TCF_META_TYPE(p->kind); switch(type) { case TCF_META_TYPE_VAR: val = malloc(len); if(!val) { rec_dbg(lev, "%s(%hu): -- %s --", name, RTA_ALIGN(meta->rta_len), strerror(errno)); return; } memset(val, 0, len); for(i = 0; i < RTA_PAYLOAD(meta); i++) val[i] = isprint(data[i]) ? data[i] : '.'; data[i] = '\0'; rec_dbg(lev, "%s(%hu): %s", name, RTA_ALIGN(meta->rta_len), data); free(val); break; case TCF_META_TYPE_INT: if(RTA_PAYLOAD(meta) < sizeof(__u32)) { rec_dbg(lev, "%s(%hu): -- payload too short --", name, RTA_ALIGN(meta->rta_len)); return; } rec_dbg(lev, "%s(%hu): %d", name, RTA_ALIGN(meta->rta_len), *(int *)RTA_DATA(meta)); break; default: rec_dbg(lev, "%s(%hu): -- unknown type(%d) --", name, RTA_ALIGN(meta->rta_len), type); return; } }
/* * parse ematch meta value */ int parse_tca_em_meta_value(char *msg, char **mp, struct tcf_meta_val *val, struct rtattr *meta) { int id = TCF_META_ID(val->kind); int type = TCF_META_TYPE(val->kind); char *data = (char *)RTA_DATA(meta); int i; if(id != TCF_META_ID_VALUE) { *mp = add_log(msg, *mp, "%s ", conv_tcf_meta_id(id, 0)); if(val->shift) *mp = add_log(msg, *mp, "shift %d ", val->shift); if(type == TCF_META_TYPE_INT && *(unsigned *)RTA_DATA(meta)) { if(RTA_PAYLOAD(meta) < sizeof(__u32)) { rec_log("error: %s: payload too short", __func__); return(1); } *mp = add_log(msg, *mp, "mask 0x%08x ", *(unsigned *)RTA_DATA(meta)); } return(0); } switch(type) { case TCF_META_TYPE_VAR: for(i = 0; i < RTA_PAYLOAD(meta); i++) *mp = add_log(msg, *mp, "%c", isprint(data[i]) ? data[i] : '.'); break; case TCF_META_TYPE_INT: if(RTA_PAYLOAD(meta) < sizeof(__u32)) { rec_log("error: %s: payload too short", __func__); return(1); } *mp = add_log(msg, *mp, "%d", *(int *)RTA_DATA(meta)); break; default: rec_log("error: %s: unknown type(%d)", __func__, type); return(1); } return(0); }
static int print_object(FILE *fd, struct tcf_meta_val *obj, struct rtattr *rta) { int id = TCF_META_ID(obj->kind); int type = TCF_META_TYPE(obj->kind); struct meta_entry *entry; if (id == TCF_META_ID_VALUE) return print_value(fd, type, rta); entry = lookup_meta_entry_byid(id); if (entry == NULL) fprintf(fd, "[unknown meta id %d]", id); else fprintf(fd, "%s", entry->kind); if (obj->shift) fprintf(fd, " shift %d", obj->shift); switch (type) { case TCF_META_TYPE_INT: if (rta) { if (RTA_PAYLOAD(rta) < sizeof(__u32)) goto size_mismatch; fprintf(fd, " mask 0x%08x", rta_getattr_u32(rta)); } break; } return 0; size_mismatch: fprintf(stderr, "meta int type mask TLV size mismatch\n"); return -1; }
static inline int meta_type(struct meta_value *v) { return TCF_META_TYPE(v->hdr.kind); }
static inline struct bstr * parse_object(struct bstr *args, struct bstr *arg, struct tcf_meta_val *obj, unsigned long *dst, struct tcf_meta_val *left) { struct meta_entry *entry; unsigned long num; struct bstr *a; if (arg->quoted) { obj->kind = TCF_META_TYPE_VAR << 12; obj->kind |= TCF_META_ID_VALUE; *dst = (unsigned long) arg; return bstr_next(arg); } num = bstrtoul(arg); if (num != ULONG_MAX) { obj->kind = TCF_META_TYPE_INT << 12; obj->kind |= TCF_META_ID_VALUE; *dst = (unsigned long) num; return bstr_next(arg); } entry = lookup_meta_entry(arg); if (entry == NULL) { PARSE_ERR(arg, "meta: unknown meta id\n"); return PARSE_FAILURE; } obj->kind = entry->id | (map_type(entry->mask[0]) << 12); if (left) { struct tcf_meta_val *right = obj; if (TCF_META_TYPE(right->kind) == TCF_META_TYPE(left->kind)) goto compatible; if (can_adopt(left) && !can_adopt(right)) { if (is_compatible(left, right)) left->kind = overwrite_type(left, right); else goto not_compatible; } else if (can_adopt(right) && !can_adopt(left)) { if (is_compatible(right, left)) right->kind = overwrite_type(right, left); else goto not_compatible; } else if (can_adopt(left) && can_adopt(right)) { if (is_compatible(left, right)) left->kind = overwrite_type(left, right); else if (is_compatible(right, left)) right->kind = overwrite_type(right, left); else goto not_compatible; } else goto not_compatible; } compatible: a = bstr_next(arg); while(a) { if (!bstrcmp(a, "shift")) { unsigned long shift; if (a->next == NULL) { PARSE_ERR(a, "meta: missing argument"); return PARSE_FAILURE; } a = bstr_next(a); shift = bstrtoul(a); if (shift == ULONG_MAX) { PARSE_ERR(a, "meta: invalid shift, must " \ "be numeric"); return PARSE_FAILURE; } obj->shift = (__u8) shift; a = bstr_next(a); } else if (!bstrcmp(a, "mask")) { unsigned long mask; if (a->next == NULL) { PARSE_ERR(a, "meta: missing argument"); return PARSE_FAILURE; } a = bstr_next(a); mask = bstrtoul(a); if (mask == ULONG_MAX) { PARSE_ERR(a, "meta: invalid mask, must be " \ "numeric"); return PARSE_FAILURE; } *dst = (unsigned long) mask; a = bstr_next(a); } else break; } return a; not_compatible: PARSE_ERR(arg, "lvalue and rvalue are not compatible."); return PARSE_FAILURE; }
static inline int overwrite_type(struct tcf_meta_val *src, struct tcf_meta_val *dst) { return (TCF_META_TYPE(dst->kind) << 12) | TCF_META_ID(src->kind); }