/* * 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; } }
/* * 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_id(struct meta_value *v) { return TCF_META_ID(v->hdr.kind); }
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); }
static inline int can_adopt(struct tcf_meta_val *val) { return !!TCF_META_ID(val->kind); }