Esempio n. 1
0
}
#endif

/* Conntrack netlink parsing. */

static bool
nl_ct_parse_counters(struct nlattr *nla, struct ct_dpif_counters *counters)
{
    static const struct nl_policy policy[] = {
        [CTA_COUNTERS_PACKETS] = { .type = NL_A_BE64, .optional = false },
        [CTA_COUNTERS_BYTES] = { .type = NL_A_BE64, .optional = false },
    };
    struct nlattr *attrs[ARRAY_SIZE(policy)];
    bool parsed;

    parsed = nl_parse_nested(nla, policy, attrs, ARRAY_SIZE(policy));

    if (parsed) {
        counters->packets
            = ntohll(nl_attr_get_be64(attrs[CTA_COUNTERS_PACKETS]));
        counters->bytes = ntohll(nl_attr_get_be64(attrs[CTA_COUNTERS_BYTES]));
    } else {
        VLOG_ERR_RL(&rl, "Could not parse nested counters. "
                    "Possibly incompatible Linux kernel version.");
    }

    return parsed;
}

static bool
nl_ct_parse_timestamp(struct nlattr *nla, struct ct_dpif_timestamp *timestamp)
Esempio n. 2
0
static int route_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
	struct nl_parser_param *pp = arg;
	struct rtnl_route route = RTNL_INIT_ROUTE();
	struct rtattr *tb[RTA_MAX + 1];
	struct rtmsg *r = NLMSG_DATA(n);
	size_t len;
	int err;

	if (n->nlmsg_type != RTM_NEWROUTE)
		return P_IGNORE;

	len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r));

	if (len < 0)
		return nl_error(EINVAL, "netlink message too short to be a " \
			"routing message");

	err = nl_parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
	if (err < 0)
		return err;

	route.rt_family = r->rtm_family;
	route.rt_dst_len = r->rtm_dst_len;
	route.rt_src_len = r->rtm_src_len;
	route.rt_tos = r->rtm_tos;
	route.rt_table = r->rtm_table;
	route.rt_protocol = r->rtm_protocol;
	route.rt_scope = r->rtm_scope;
	route.rt_type = r->rtm_type;
	route.rt_flags = r->rtm_flags;

	route.rt_mask = (ROUTE_HAS_FAMILY|ROUTE_HAS_DST_LEN|ROUTE_HAS_SRC_LEN|
		ROUTE_HAS_TOS|ROUTE_HAS_TABLE|ROUTE_HAS_PROTOCOL|ROUTE_HAS_SCOPE|
		ROUTE_HAS_TYPE|ROUTE_HAS_FLAGS);

	if (tb[RTA_DST]) {
		nl_copy_addr(&route.rt_dst, tb[RTA_DST]);
		route.rt_dst.a_prefix = route.rt_dst_len;
		route.rt_dst.a_family = route.rt_family;
		route.rt_mask |= ROUTE_HAS_DST;
	}

	if (tb[RTA_SRC]) {
		nl_copy_addr(&route.rt_src, tb[RTA_SRC]);
		route.rt_src.a_prefix = route.rt_src_len;
		route.rt_src.a_family = route.rt_family;
		route.rt_mask |= ROUTE_HAS_SRC;
	}

	if (tb[RTA_IIF]) {
		err = NL_COPY_DATA(route.rt_iif, tb[RTA_IIF]);
		if (err < 0)
			return err;
		route.rt_mask |= ROUTE_HAS_IIF;
	}

	if (tb[RTA_OIF]) {
		err = NL_COPY_DATA(route.rt_oif, tb[RTA_OIF]);
		if (err < 0)
			return err;
		route.rt_mask |= ROUTE_HAS_OIF;
	}

	if (tb[RTA_GATEWAY]) {
		nl_copy_addr(&route.rt_gateway, tb[RTA_GATEWAY]);
		route.rt_gateway.a_family = route.rt_family;
		route.rt_mask |= ROUTE_HAS_GATEWAY;
	}

	if (tb[RTA_PRIORITY]) {
		err = NL_COPY_DATA(route.rt_prio, tb[RTA_PRIORITY]);
		if (err < 0)
			return err;
		route.rt_mask |= ROUTE_HAS_PRIO;
	}

	if (tb[RTA_PREFSRC]) {
		nl_copy_addr(&route.rt_pref_src, tb[RTA_PREFSRC]);
		route.rt_pref_src.a_family = route.rt_family;
		route.rt_mask |= ROUTE_HAS_PREF_SRC;
	}

	if (tb[RTA_METRICS]) {
		int i;
		struct rtattr *mtb[RTAX_MAX + 1];

		err = nl_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS]);
		if (err < 0)
			return err;

		for (i = 1; i <= RTAX_MAX; i++) {
			if (mtb[i]) {
				uint32_t m = *(uint32_t *) RTA_DATA(mtb[i]);
				route.rt_metrics[i] = m;
				route.rt_metrics_mask |= (1<<(i-1));
			}
		}
		
		route.rt_mask |= ROUTE_HAS_METRICS;
	}

	if (tb[RTA_MULTIPATH]) {
		struct rtnl_nexthop *nh;
		struct rtnexthop *rtnh = RTA_DATA(tb[RTA_MULTIPATH]);
		size_t tlen = RTA_PAYLOAD(tb[RTA_MULTIPATH]);

		for (;;) {
			if (tlen < sizeof(*rtnh) || tlen < rtnh->rtnh_len)
				break;

			nh = calloc(1, sizeof(*nh));
			if (nh == NULL) {
				err = -ENOMEM;
				goto err_out;
			}

			nh->rtnh_flags = rtnh->rtnh_flags;
			nh->rtnh_hops = rtnh->rtnh_hops;
			nh->rtnh_ifindex = rtnh->rtnh_ifindex;
			nh->rtnh_mask = (NEXTHOP_HAS_FLAGS | NEXTHOP_HAS_HOPS
					| NEXTHOP_HAS_IFINDEX);
				
			if (rtnh->rtnh_len > sizeof(*rtnh)) {
				struct rtattr *ntb[RTA_MAX + 1];
				nl_parse_rtattr(ntb, RTA_MAX, RTNH_DATA(rtnh),
					rtnh->rtnh_len - sizeof(*rtnh));

				if (ntb[RTA_GATEWAY]) {
					nl_copy_addr(&nh->rtnh_gateway, ntb[RTA_GATEWAY]);
					nh->rtnh_gateway.a_family = route.rt_family;
					nh->rtnh_mask = NEXTHOP_HAS_GATEWAY;
				}
			}

			nh->rtnh_next = route.rt_nexthops;
			route.rt_nexthops = nh;

			len -= RTNH_ALIGN(rtnh->rtnh_len);
			rtnh = RTNH_NEXT(rtnh);
		}

		route.rt_mask |= ROUTE_HAS_MULTIPATH;
	}

	/* Not sure if there are any users not using this for fwmark,
	 * allocating for now */
	if (tb[RTA_PROTOINFO]) {
		err = nl_alloc_data_from_rtattr(&route.rt_protoinfo, tb[RTA_PROTOINFO]);
		if (err < 0)
			goto err_out;
		route.rt_mask |= ROUTE_HAS_PROTOINFO;
	}

	if (tb[RTA_FLOW]) {
		err = NL_COPY_DATA(route.rt_realm, tb[RTA_FLOW]);
		if (err < 0)
			goto err_out;
		route.rt_mask |= ROUTE_HAS_REALM;
	}

	if (tb[RTA_CACHEINFO]) {
		struct rta_cacheinfo *ci;
		
		if (RTA_PAYLOAD(tb[RTA_CACHEINFO]) < sizeof(struct rta_cacheinfo))
			return nl_error(EINVAL, "routing cacheinfo TLV is too short");

		ci = (struct rta_cacheinfo *) RTA_DATA(tb[RTA_CACHEINFO]);
		route.rt_cacheinfo.rtci_clntref  = ci->rta_clntref;
		route.rt_cacheinfo.rtci_last_use = ci->rta_lastuse;
		route.rt_cacheinfo.rtci_expires  = ci->rta_expires;
		route.rt_cacheinfo.rtci_error    = ci->rta_error;
		route.rt_cacheinfo.rtci_used     = ci->rta_used;
		route.rt_cacheinfo.rtci_id       = ci->rta_id;
		route.rt_cacheinfo.rtci_ts       = ci->rta_ts;
		route.rt_cacheinfo.rtci_tsage    = ci->rta_tsage;

		route.rt_mask |= ROUTE_HAS_CACHEINFO;
	}

	if (tb[RTA_SESSION]) {
		err = nl_alloc_data_from_rtattr(&route.rt_session, tb[RTA_SESSION]);
		if (err < 0)
			goto err_out;
		route.rt_mask |= ROUTE_HAS_SESSION;
	}

	err = pp->pp_cb((struct nl_common *) &route, pp);
	if (err < 0)
		goto err_out;

	return P_ACCEPT;

err_out:

	route_free_data((struct nl_common *) &route);
	return err;
}