コード例 #1
0
ファイル: vrrp_iproute.c プロジェクト: soarpenguin/keepalived
static void
add_encap_ip6(struct rtattr *rta, size_t len, const encap_t *encap)
{
	if (encap->flags & IPROUTE_BIT_ENCAP_ID)
		rta_addattr64(rta, len, LWTUNNEL_IP6_ID, htonll(encap->ip6.id));
	if (encap->ip6.dst)
		rta_addattr_l(rta, len, LWTUNNEL_IP6_DST, &encap->ip6.dst->u.sin6_addr, sizeof(encap->ip6.dst->u.sin6_addr));
	if (encap->ip6.src)
		rta_addattr_l(rta, len, LWTUNNEL_IP6_SRC, &encap->ip6.src->u.sin6_addr, sizeof(encap->ip6.src->u.sin6_addr));
	if (encap->flags & IPROUTE_BIT_ENCAP_DSFIELD)
		rta_addattr8(rta, len, LWTUNNEL_IP6_TC, encap->ip6.tc);
	if (encap->flags & IPROUTE_BIT_ENCAP_HOPLIMIT)
		rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT, encap->ip6.hoplimit);
	if (encap->flags & IPROUTE_BIT_ENCAP_FLAGS)
		rta_addattr16(rta, len, LWTUNNEL_IP6_FLAGS, encap->ip6.flags);
}
コード例 #2
0
ファイル: vrrp_iproute.c プロジェクト: soarpenguin/keepalived
static void
add_encap_ip(struct rtattr *rta, size_t len, const encap_t *encap)
{
	if (encap->flags & IPROUTE_BIT_ENCAP_ID)
		rta_addattr64(rta, len, LWTUNNEL_IP_ID, htonll(encap->ip.id));
	if (encap->ip.dst)
		rta_addattr_l(rta, len, LWTUNNEL_IP_DST, &encap->ip.dst->u.sin.sin_addr.s_addr, sizeof(encap->ip.dst->u.sin.sin_addr.s_addr));
	if (encap->ip.src)
		rta_addattr_l(rta, len, LWTUNNEL_IP_SRC, &encap->ip.src->u.sin.sin_addr.s_addr, sizeof(encap->ip.src->u.sin.sin_addr.s_addr));
	if (encap->flags & IPROUTE_BIT_ENCAP_DSFIELD)
		rta_addattr8(rta, len, LWTUNNEL_IP_TOS, encap->ip.tos);
	if (encap->flags & IPROUTE_BIT_ENCAP_HOPLIMIT)
		rta_addattr8(rta, len, LWTUNNEL_IP_TTL, encap->ip.ttl);
	if (encap->flags & IPROUTE_BIT_ENCAP_FLAGS)
		rta_addattr16(rta, len, LWTUNNEL_IP_FLAGS, encap->ip.flags);
}
コード例 #3
0
ファイル: vrrp_netlink.c プロジェクト: Oefenweb/keepalived
struct rtattr *
rta_nest(struct rtattr *rta, size_t maxlen, unsigned short type)
{
	struct rtattr *nest = RTA_TAIL(rta);

	rta_addattr_l(rta, maxlen, type, NULL, 0);

	return nest;
}
コード例 #4
0
static int parse_encap_ip6(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
{
	int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
	char **argv = *argvp;
	int argc = *argcp;

	while (argc > 0) {
		if (strcmp(*argv, "id") == 0) {
			__u64 id;

			NEXT_ARG();
			if (id_ok++)
				duparg2("id", *argv);
			if (get_be64(&id, *argv, 0))
				invarg("\"id\" value is invalid\n", *argv);
			rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id);
		} else if (strcmp(*argv, "dst") == 0) {
			inet_prefix addr;

			NEXT_ARG();
			if (dst_ok++)
				duparg2("dst", *argv);
			get_addr(&addr, *argv, AF_INET6);
			rta_addattr_l(rta, len, LWTUNNEL_IP6_DST, &addr.data, addr.bytelen);
		} else if (strcmp(*argv, "tc") == 0) {
			__u32 tc;

			NEXT_ARG();
			if (tos_ok++)
				duparg2("tc", *argv);
			if (rtnl_dsfield_a2n(&tc, *argv))
				invarg("\"tc\" value is invalid\n", *argv);
			rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc);
		} else if (strcmp(*argv, "hoplimit") == 0) {
			__u8 hoplimit;

			NEXT_ARG();
			if (ttl_ok++)
				duparg2("hoplimit", *argv);
			if (get_u8(&hoplimit, *argv, 0))
				invarg("\"hoplimit\" value is invalid\n", *argv);
			rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT, hoplimit);
		} else {
			break;
		}
		argc--; argv++;
	}

	/* argv is currently the first unparsed argument,
	 * but the lwt_parse_encap() caller will move to the next,
	 * so step back */
	*argcp = argc + 1;
	*argvp = argv - 1;

	return 0;
}
コード例 #5
0
ファイル: vrrp_iproute.c プロジェクト: Zex/keepalived
static int
add_addr2rta(struct rtattr *rta, int maxlen, int type, ip_address_t *ip_address)
{
	void *addr;
	int alen;

	if (!ip_address)
		return -1;

	addr = (IP_IS6(ip_address)) ? (void *) &ip_address->u.sin6_addr :
				     (void *) &ip_address->u.sin.sin_addr;
	alen = (IP_IS6(ip_address)) ? sizeof(ip_address->u.sin6_addr) :
				     sizeof(ip_address->u.sin.sin_addr);

	return rta_addattr_l(rta, maxlen, type, addr, alen);
}
コード例 #6
0
static int parse_encap_mpls(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
{
	inet_prefix addr;
	int argc = *argcp;
	char **argv = *argvp;

	if (get_addr(&addr, *argv, AF_MPLS)) {
		fprintf(stderr, "Error: an inet address is expected rather than \"%s\".\n", *argv);
		exit(1);
	}

	rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST, &addr.data,
		      addr.bytelen);

	*argcp = argc;
	*argvp = argv;

	return 0;
}
コード例 #7
0
/* Routing table change via netlink interface. */
int
netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
                         int family)
{
    int bytelen;
    struct sockaddr_nl snl;
    struct nexthop *nexthop = NULL;
    int nexthop_num = 0;
    struct nlsock *nl;

    struct
    {
        struct nlmsghdr n;
        struct rtmsg r;
        char buf[1024];
    } req;

    memset (&req, 0, sizeof req);

    bytelen = (family == AF_INET ? 4 : 16);

    req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
    req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
    req.n.nlmsg_type = cmd;
    req.r.rtm_family = family;
    req.r.rtm_table = rib->table;
    req.r.rtm_dst_len = p->prefixlen;

    if (cmd == RTM_NEWROUTE)
    {
        req.r.rtm_protocol = RTPROT_ZEBRA;
        req.r.rtm_scope = RT_SCOPE_UNIVERSE;

        if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
            req.r.rtm_type = RTN_BLACKHOLE;
        else
            req.r.rtm_type = RTN_UNICAST;
    }

    addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);

    /* Metric. */
    addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);

    /* Multipath case. */
    if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
    {
        for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
        {
            if ((cmd == RTM_NEWROUTE
                    && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
                    || (cmd == RTM_DELROUTE
                        && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
            {
                if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
                {
                    if (nexthop->rtype == NEXTHOP_TYPE_IPV4
                            || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
                        addattr_l (&req.n, sizeof req, RTA_GATEWAY,
                                   &nexthop->rgate.ipv4, bytelen);
#ifdef HAVE_IPV6
                    if (nexthop->rtype == NEXTHOP_TYPE_IPV6
                            || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
                            || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
                        addattr_l (&req.n, sizeof req, RTA_GATEWAY,
                                   &nexthop->rgate.ipv6, bytelen);
#endif /* HAVE_IPV6 */
                    if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
                            || nexthop->rtype == NEXTHOP_TYPE_IFNAME
                            || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
                            || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
                            || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
                        addattr32 (&req.n, sizeof req, RTA_OIF,
                                   nexthop->rifindex);
                }
                else
                {
                    if (nexthop->type == NEXTHOP_TYPE_IPV4
                            || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
                        addattr_l (&req.n, sizeof req, RTA_GATEWAY,
                                   &nexthop->gate.ipv4, bytelen);
#ifdef HAVE_IPV6
                    if (nexthop->type == NEXTHOP_TYPE_IPV6
                            || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
                            || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
                        addattr_l (&req.n, sizeof req, RTA_GATEWAY,
                                   &nexthop->gate.ipv6, bytelen);
#endif /* HAVE_IPV6 */
                    if (nexthop->type == NEXTHOP_TYPE_IFINDEX
                            || nexthop->type == NEXTHOP_TYPE_IFNAME
                            || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
                            || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
                            || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
                        addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
                }

                if (cmd == RTM_NEWROUTE)
                    SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);

                nexthop_num++;
                break;
            }
        }
    }
    else
    {
        char buf[1024];
        struct rtattr *rta = (void *) buf;
        struct rtnexthop *rtnh;

        rta->rta_type = RTA_MULTIPATH;
        rta->rta_len = RTA_LENGTH(0);
        rtnh = RTA_DATA(rta);

        nexthop_num = 0;
        for (nexthop = rib->nexthop;
                nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
                nexthop = nexthop->next)
        {
            if ((cmd == RTM_NEWROUTE
                    && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
                    || (cmd == RTM_DELROUTE
                        && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
            {
                nexthop_num++;

                rtnh->rtnh_len = sizeof (*rtnh);
                rtnh->rtnh_flags = 0;
                rtnh->rtnh_hops = 0;
                rta->rta_len += rtnh->rtnh_len;

                if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
                {
                    if (nexthop->rtype == NEXTHOP_TYPE_IPV4
                            || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
                    {
                        rta_addattr_l (rta, 4096, RTA_GATEWAY,
                                       &nexthop->rgate.ipv4, bytelen);
                        rtnh->rtnh_len += sizeof (struct rtattr) + 4;
                    }
#ifdef HAVE_IPV6
                    if (nexthop->rtype == NEXTHOP_TYPE_IPV6
                            || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
                            || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
                        rta_addattr_l (rta, 4096, RTA_GATEWAY,
                                       &nexthop->rgate.ipv6, bytelen);
#endif /* HAVE_IPV6 */
                    /* ifindex */
                    if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
                            || nexthop->rtype == NEXTHOP_TYPE_IFNAME
                            || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
                            || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
                            || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
                        rtnh->rtnh_ifindex = nexthop->rifindex;
                    else
                        rtnh->rtnh_ifindex = 0;
                }
                else
                {
                    if (nexthop->type == NEXTHOP_TYPE_IPV4
                            || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
                    {
                        rta_addattr_l (rta, 4096, RTA_GATEWAY,
                                       &nexthop->gate.ipv4, bytelen);
                        rtnh->rtnh_len += sizeof (struct rtattr) + 4;
                    }
#ifdef HAVE_IPV6
                    if (nexthop->type == NEXTHOP_TYPE_IPV6
                            || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
                            || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
                        rta_addattr_l (rta, 4096, RTA_GATEWAY,
                                       &nexthop->gate.ipv6, bytelen);
#endif /* HAVE_IPV6 */
                    /* ifindex */
                    if (nexthop->type == NEXTHOP_TYPE_IFINDEX
                            || nexthop->type == NEXTHOP_TYPE_IFNAME
                            || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
                            || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
                            || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
                        rtnh->rtnh_ifindex = nexthop->ifindex;
                    else
                        rtnh->rtnh_ifindex = 0;
                }
                rtnh = RTNH_NEXT(rtnh);

                if (cmd == RTM_NEWROUTE)
                    SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
            }
        }

        if (rta->rta_len > RTA_LENGTH (0))
            addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA(rta),
                       RTA_PAYLOAD(rta));
    }

    /* If there is no useful nexthop then return. */
    if (nexthop_num == 0)
    {
        if (IS_ZEBRA_DEBUG_KERNEL)
            zlog_info ("netlink_route_multipath(): No useful nexthop.");
        return 0;
    }

    /* Destination netlink address. */
    memset (&snl, 0, sizeof snl);
    snl.nl_family = AF_NETLINK;

    if (family == AF_INET)
        nl = &netlink_cmd;
    else
        nl = &netlink;

    /* Talk to netlink socket. */
    return netlink_talk (&req.n, nl);
}
コード例 #8
0
ファイル: ipntable.c プロジェクト: flwh/Alcatel_OT_985_kernel
static int ipntable_modify(int cmd, int flags, int argc, char **argv)
{
	struct {
		struct nlmsghdr 	n;
		struct ndtmsg		ndtm;
		char   			buf[1024];
	} req;
	char *namep = NULL;
	char *threshsp = NULL;
	char *gc_intp = NULL;
	char parms_buf[1024];
	struct rtattr *parms_rta = (struct rtattr *)parms_buf;
	int parms_change = 0;

	memset(&req, 0, sizeof(req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
	req.n.nlmsg_type = cmd;

	req.ndtm.ndtm_family = preferred_family;
	req.ndtm.ndtm_pad1 = 0;
	req.ndtm.ndtm_pad2 = 0;

	memset(&parms_buf, 0, sizeof(parms_buf));

	parms_rta->rta_type = NDTA_PARMS;
	parms_rta->rta_len = RTA_LENGTH(0);

	while (argc > 0) {
		if (strcmp(*argv, "name") == 0) {
			int len;

			NEXT_ARG();
			if (namep)
				duparg("NAME", *argv);

			namep = *argv;
			len = strlen(namep) + 1;
			addattr_l(&req.n, sizeof(req), NDTA_NAME, namep, len);
		} else if (strcmp(*argv, "thresh1") == 0) {
			__u32 thresh1;

			NEXT_ARG();
			threshsp = *argv;

			if (get_u32(&thresh1, *argv, 0))
				invarg("\"thresh1\" value is invalid", *argv);

			addattr32(&req.n, sizeof(req), NDTA_THRESH1, thresh1);
		} else if (strcmp(*argv, "thresh2") == 0) {
			__u32 thresh2;

			NEXT_ARG();
			threshsp = *argv;

			if (get_u32(&thresh2, *argv, 0))
				invarg("\"thresh2\" value is invalid", *argv);

			addattr32(&req.n, sizeof(req), NDTA_THRESH2, thresh2);
		} else if (strcmp(*argv, "thresh3") == 0) {
			__u32 thresh3;

			NEXT_ARG();
			threshsp = *argv;

			if (get_u32(&thresh3, *argv, 0))
				invarg("\"thresh3\" value is invalid", *argv);

			addattr32(&req.n, sizeof(req), NDTA_THRESH3, thresh3);
		} else if (strcmp(*argv, "gc_int") == 0) {
			__u64 gc_int;

			NEXT_ARG();
			gc_intp = *argv;

			if (get_u64(&gc_int, *argv, 0))
				invarg("\"gc_int\" value is invalid", *argv);

			addattr_l(&req.n, sizeof(req), NDTA_GC_INTERVAL,
				  &gc_int, sizeof(gc_int));
		} else if (strcmp(*argv, "dev") == 0) {
			__u32 ifindex;

			NEXT_ARG();
			ifindex = ll_name_to_index(*argv);
			if (ifindex == 0) {
				fprintf(stderr, "Cannot find device \"%s\"\n", *argv);
				return -1;
			}

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_IFINDEX, ifindex);
		} else if (strcmp(*argv, "base_reachable") == 0) {
			__u64 breachable;

			NEXT_ARG();

			if (get_u64(&breachable, *argv, 0))
				invarg("\"base_reachable\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_BASE_REACHABLE_TIME,
				      &breachable, sizeof(breachable));
			parms_change = 1;
		} else if (strcmp(*argv, "retrans") == 0) {
			__u64 retrans;

			NEXT_ARG();

			if (get_u64(&retrans, *argv, 0))
				invarg("\"retrans\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_RETRANS_TIME,
				      &retrans, sizeof(retrans));
			parms_change = 1;
		} else if (strcmp(*argv, "gc_stale") == 0) {
			__u64 gc_stale;

			NEXT_ARG();

			if (get_u64(&gc_stale, *argv, 0))
				invarg("\"gc_stale\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_GC_STALETIME,
				      &gc_stale, sizeof(gc_stale));
			parms_change = 1;
		} else if (strcmp(*argv, "delay_probe") == 0) {
			__u64 delay_probe;

			NEXT_ARG();

			if (get_u64(&delay_probe, *argv, 0))
				invarg("\"delay_probe\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_DELAY_PROBE_TIME,
				      &delay_probe, sizeof(delay_probe));
			parms_change = 1;
		} else if (strcmp(*argv, "queue") == 0) {
			__u32 queue;

			NEXT_ARG();

			if (get_u32(&queue, *argv, 0))
				invarg("\"queue\" value is invalid", *argv);

			if (!parms_rta)
				parms_rta = (struct rtattr *)&parms_buf;
			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_QUEUE_LEN, queue);
			parms_change = 1;
		} else if (strcmp(*argv, "app_probes") == 0) {
			__u32 aprobe;

			NEXT_ARG();

			if (get_u32(&aprobe, *argv, 0))
				invarg("\"app_probes\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_APP_PROBES, aprobe);
			parms_change = 1;
		} else if (strcmp(*argv, "ucast_probes") == 0) {
			__u32 uprobe;

			NEXT_ARG();

			if (get_u32(&uprobe, *argv, 0))
				invarg("\"ucast_probes\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_UCAST_PROBES, uprobe);
			parms_change = 1;
		} else if (strcmp(*argv, "mcast_probes") == 0) {
			__u32 mprobe;

			NEXT_ARG();

			if (get_u32(&mprobe, *argv, 0))
				invarg("\"mcast_probes\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_MCAST_PROBES, mprobe);
			parms_change = 1;
		} else if (strcmp(*argv, "anycast_delay") == 0) {
			__u64 anycast_delay;

			NEXT_ARG();

			if (get_u64(&anycast_delay, *argv, 0))
				invarg("\"anycast_delay\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_ANYCAST_DELAY,
				      &anycast_delay, sizeof(anycast_delay));
			parms_change = 1;
		} else if (strcmp(*argv, "proxy_delay") == 0) {
			__u64 proxy_delay;

			NEXT_ARG();

			if (get_u64(&proxy_delay, *argv, 0))
				invarg("\"proxy_delay\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_PROXY_DELAY,
				      &proxy_delay, sizeof(proxy_delay));
			parms_change = 1;
		} else if (strcmp(*argv, "proxy_queue") == 0) {
			__u32 pqueue;

			NEXT_ARG();

			if (get_u32(&pqueue, *argv, 0))
				invarg("\"proxy_queue\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_PROXY_QLEN, pqueue);
			parms_change = 1;
		} else if (strcmp(*argv, "locktime") == 0) {
			__u64 locktime;

			NEXT_ARG();

			if (get_u64(&locktime, *argv, 0))
				invarg("\"locktime\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_LOCKTIME,
				      &locktime, sizeof(locktime));
			parms_change = 1;
		} else {
			invarg("unknown", *argv);
		}

		argc--; argv++;
	}

	if (!namep)
		missarg("NAME");
	if (!threshsp && !gc_intp && !parms_change) {
		fprintf(stderr, "Not enough information: changable attributes required.\n");
		exit(-1);
	}

	if (parms_rta->rta_len > RTA_LENGTH(0)) {
		addattr_l(&req.n, sizeof(req), NDTA_PARMS, RTA_DATA(parms_rta),
			  RTA_PAYLOAD(parms_rta));
	}

	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
		exit(2);

	return 0;
}
コード例 #9
0
ファイル: vrrp_iproute.c プロジェクト: soarpenguin/keepalived
/* Add/Delete IP route to/from a specific interface */
static int
netlink_route(ip_route_t *iproute, int cmd)
{
	int status = 1;
	struct {
		struct nlmsghdr n;
		struct rtmsg r;
		char buf[RTM_SIZE];
	} req;
	char buf[RTA_SIZE];
	struct rtattr *rta = (void*)buf;

	memset(&req, 0, sizeof (req));

	req.n.nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtmsg));
	if (cmd == IPROUTE_DEL) {
		req.n.nlmsg_flags = NLM_F_REQUEST;
		req.n.nlmsg_type  = RTM_DELROUTE;
	}
	else {
		req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
		if (cmd == IPROUTE_REPLACE)
			req.n.nlmsg_flags |= NLM_F_REPLACE;
		req.n.nlmsg_type  = RTM_NEWROUTE;
	}

	rta->rta_type = RTA_METRICS;
	rta->rta_len = RTA_LENGTH(0);

	req.r.rtm_family = iproute->family;
	if (iproute->table < 256)
		req.r.rtm_table = iproute->table;
	else {
		req.r.rtm_table = RT_TABLE_UNSPEC;
		addattr32(&req.n, sizeof(req), RTA_TABLE, iproute->table);
	}

	if (cmd == IPROUTE_DEL) {
		req.r.rtm_scope = RT_SCOPE_NOWHERE;
		if (iproute->mask & IPROUTE_BIT_TYPE)
			req.r.rtm_type = iproute->type;
	}
	else {
		req.r.rtm_protocol = RTPROT_BOOT;
		req.r.rtm_scope = RT_SCOPE_UNIVERSE;
		req.r.rtm_type = iproute->type;
	}

	if (iproute->mask & IPROUTE_BIT_PROTOCOL)
		req.r.rtm_protocol = iproute->protocol;

	if (iproute->mask & IPROUTE_BIT_SCOPE)
		req.r.rtm_scope = iproute->scope;

	if (iproute->dst) {
		req.r.rtm_dst_len = iproute->dst->ifa.ifa_prefixlen;
		add_addr2req(&req.n, sizeof(req), RTA_DST, iproute->dst);
	}

	if (iproute->src) {
		req.r.rtm_src_len = iproute->src->ifa.ifa_prefixlen;
		add_addr2req(&req.n, sizeof(req), RTA_SRC, iproute->src);
	}

	if (iproute->pref_src)
		add_addr2req(&req.n, sizeof(req), RTA_PREFSRC, iproute->pref_src);

//#ifdef _HAVE_RTA_NEWDST_
//	if (iproute->as_to)
//		add_addr2req(&req.n, sizeof(req), RTA_NEWDST, iproute->as_to);
//#endif

	if (iproute->via) {
		if (iproute->via->ifa.ifa_family == iproute->family)
			add_addr2req(&req.n, sizeof(req), RTA_GATEWAY, iproute->via);
#ifdef _HAVE_RTA_VIA_
		else
			add_addr_fam2req(&req.n, sizeof(req), RTA_VIA, iproute->via);
#endif
	}

#ifdef _HAVE_RTA_ENCAP_
	if (iproute->encap.type != LWTUNNEL_ENCAP_NONE) {
		char encap_buf[ENCAP_RTA_SIZE];
		struct rtattr *encap_rta = (void *)encap_buf;

		encap_rta->rta_type = RTA_ENCAP;
		encap_rta->rta_len = RTA_LENGTH(0);
		add_encap(encap_rta, sizeof(encap_buf), &iproute->encap);

		if (encap_rta->rta_len > RTA_LENGTH(0))
			addraw_l(&req.n, sizeof(encap_buf), RTA_DATA(encap_rta), RTA_PAYLOAD(encap_rta));
	}
#endif

	if (iproute->mask & IPROUTE_BIT_DSFIELD)
		req.r.rtm_tos = iproute->tos;
	
	if (iproute->oif)
		addattr32(&req.n, sizeof(req), RTA_OIF, iproute->oif->ifindex);

	if (iproute->mask & IPROUTE_BIT_METRIC)
		addattr32(&req.n, sizeof(req), RTA_PRIORITY, iproute->metric);

	req.r.rtm_flags = iproute->flags;

	if (iproute->realms)
		addattr32(&req.n, sizeof(req), RTA_FLOW, iproute->realms);

#ifdef _HAVE_RTA_EXPIRES_
	if (iproute->mask & IPROUTE_BIT_EXPIRES)
		addattr32(&req.n, sizeof(req), RTA_EXPIRES, iproute->expires);
#endif

#ifdef RTAX_CC_ALGO
	if (iproute->congctl)
		rta_addattr_l(rta, sizeof(buf), RTAX_CC_ALGO, iproute->congctl, strlen(iproute->congctl));
#endif

	if (iproute->mask & IPROUTE_BIT_RTT)
		rta_addattr32(rta, sizeof(buf), RTAX_RTT, iproute->rtt);

	if (iproute->mask & IPROUTE_BIT_RTTVAR)
		rta_addattr32(rta, sizeof(buf), RTAX_RTTVAR, iproute->rttvar);

	if (iproute->mask & IPROUTE_BIT_RTO_MIN)
		rta_addattr32(rta, sizeof(buf), RTAX_RTO_MIN, iproute->rto_min);

#ifdef RTAX_FEATURES
	if (iproute->features)
		rta_addattr32(rta, sizeof(buf), RTAX_FEATURES, iproute->features);
#endif

	if (iproute->mask & IPROUTE_BIT_MTU)
		rta_addattr32(rta, sizeof(buf), RTAX_MTU, iproute->mtu);

	if (iproute->mask & IPROUTE_BIT_WINDOW)
		rta_addattr32(rta, sizeof(buf), RTAX_WINDOW, iproute->window);

	if (iproute->mask & IPROUTE_BIT_SSTHRESH)
		rta_addattr32(rta, sizeof(buf), RTAX_SSTHRESH, iproute->ssthresh);

	if (iproute->mask & IPROUTE_BIT_CWND)
		rta_addattr32(rta, sizeof(buf), RTAX_CWND, iproute->cwnd);

	if (iproute->mask & IPROUTE_BIT_ADVMSS)
		rta_addattr32(rta, sizeof(buf), RTAX_ADVMSS, iproute->advmss);

	if (iproute->mask & IPROUTE_BIT_REORDERING)
		rta_addattr32(rta, sizeof(buf), RTAX_REORDERING, iproute->reordering);

	if (iproute->mask & IPROUTE_BIT_HOPLIMIT)
		rta_addattr32(rta, sizeof(buf), RTAX_HOPLIMIT, iproute->hoplimit);

	if (iproute->mask & IPROUTE_BIT_INITCWND)
		rta_addattr32(rta, sizeof(buf), RTAX_INITCWND, iproute->initcwnd);

#ifdef RTAX_INITRWND
	if (iproute->mask & IPROUTE_BIT_INITRWND)
		rta_addattr32(rta, sizeof(buf), RTAX_INITRWND, iproute->initrwnd);
#endif

#ifdef RTAX_QUICKACK
	if (iproute->mask & IPROUTE_BIT_QUICKACK)
		rta_addattr32(rta, sizeof(buf), RTAX_QUICKACK, iproute->quickack);
#endif

#ifdef _HAVE_RTA_PREF_
	if (iproute->mask & IPROUTE_BIT_PREF)
		addattr8(&req.n, sizeof(req), RTA_PREF, iproute->pref);
#endif

	if (rta->rta_len > RTA_LENGTH(0)) {
		if (iproute->lock)
			rta_addattr32(rta, sizeof(buf), RTAX_LOCK, iproute->lock);
		addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(rta), RTA_PAYLOAD(rta));
	}

	if (!LIST_ISEMPTY(iproute->nhs))
		add_nexthops(iproute, &req.n, &req.r);

#ifdef DEBUG_NETLINK_MSG
	size_t i, j;
	uint8_t *p;
	char lbuf[3072];
	char *op = lbuf;

	log_message(LOG_INFO, "rtmsg buffer used %lu, rtattr buffer used %d", req.n.nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)), rta->rta_len);

	op += snprintf(op, sizeof(lbuf) - (op - lbuf), "nlmsghdr %p(%u):", &req.n, req.n.nlmsg_len);
	for (i = 0, p = (uint8_t*)&req.n; i < sizeof(struct nlmsghdr); i++)
		op += snprintf(op, sizeof(lbuf) - (op - lbuf), " %2.2hhx", *(p++));
	log_message(LOG_INFO, "%s\n", lbuf);

	op = lbuf;
	op += snprintf(op, sizeof(lbuf) - (op - lbuf), "rtmsg %p(%lu):", &req.r, req.n.nlmsg_len - sizeof(struct nlmsghdr));
	for (i = 0, p = (uint8_t*)&req.r; i < + req.n.nlmsg_len - sizeof(struct nlmsghdr); i++)
		op += snprintf(op, sizeof(lbuf) - (op - lbuf), " %2.2hhx", *(p++));

	for (j = 0; lbuf + j < op; j+= MAX_LOG_MSG)
		log_message(LOG_INFO, "%.*\n", MAX_LOG_MSG, lbuf+j);
#endif

	/* This returns ESRCH if the address of via address doesn't exist */
	/* ENETDOWN if dev p33p1.40 for example is down */
	if (netlink_talk(&nl_cmd, &req.n) < 0) {
#ifdef _HAVE_RTA_EXPIRES_
		/* If an expiry was set on the route, it may have disappeared already */
		if (cmd != IPADDRESS_DEL || !(iproute->mask & IPROUTE_BIT_EXPIRES))
#endif
			status = -1;
	}

	return status;
}
コード例 #10
0
ファイル: vrrp_iproute.c プロジェクト: soarpenguin/keepalived
static void
add_encap_mpls(struct rtattr *rta, size_t len, const encap_t *encap)
{
	rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST, &encap->mpls.addr, encap->mpls.num_labels * sizeof(encap->mpls.addr[0]));
}
コード例 #11
0
ファイル: vrrp_netlink.c プロジェクト: Oefenweb/keepalived
size_t
rta_addattr8(struct rtattr *rta, size_t maxlen, unsigned short type, uint8_t data)
{
	return rta_addattr_l(rta, maxlen, type, &data, sizeof data);
}
コード例 #12
0
ファイル: krnl_route.c プロジェクト: Netsukuku/netsukuku
int
add_nexthops(struct nlmsghdr *n, struct rtmsg *r, struct nexthop *nhop)
{
	char buf[1024];
	struct rtattr *rta = (void *) buf;
	struct rtnexthop *rtnh;
	int i = 0, idx;

	rta->rta_type = RTA_MULTIPATH;
	rta->rta_len = RTA_LENGTH(0);
	rtnh = RTA_DATA(rta);

	if (!nhop[i + 1].dev) {
		/* Just one gateway */
		r->rtm_family = nhop[i].gw.family;
		addattr_l(n, sizeof(struct rt_request), RTA_GATEWAY,
				  &nhop[i].gw.data, nhop[i].gw.len);

		if (nhop[0].dev) {
			if ((idx = ll_name_to_index(nhop[0].dev)) == 0) {
				error(ERROR_MSG "Device \"%s\" doesn't really exist\n",
					  ERROR_POS, nhop[0].dev);
				return -1;
			}
			addattr32(n, sizeof(struct rt_request), RTA_OIF, idx);
		}

		return 0;
	}
#if 0
	/* We have more than one nexthop, equalize them */
	req.rt.rtm_flags |= RTM_F_EQUALIZE;
#endif

	while (nhop[i].dev != 0) {
		setzero(rtnh, sizeof(*rtnh));
		rtnh->rtnh_len = sizeof(*rtnh);
		rta->rta_len += rtnh->rtnh_len;

		if (nhop[i].gw.len) {
			if (nhop[i].gw.family == AF_INET)
				rta_addattr32(rta, 4096, RTA_GATEWAY, nhop[i].gw.data[0]);
			else if (nhop[i].gw.family == AF_INET6)
				rta_addattr_l(rta, 4096, RTA_GATEWAY, nhop[i].gw.data,
							  nhop[i].gw.len);
			rtnh->rtnh_len += sizeof(struct rtattr) + nhop[i].gw.len;
		}

		if (nhop[i].dev)
			if ((rtnh->rtnh_ifindex = ll_name_to_index(nhop[i].dev)) == 0)
				fatal("%s:%d, Cannot find device \"%s\"\n", ERROR_POS,
					  nhop[i].dev);

		if (nhop[i].hops == 0) {
			debug(DBG_NORMAL, "hops=%d is invalid. Using hops=255\n",
				  nhop[i].hops);
			rtnh->rtnh_hops = 255;
		} else
			rtnh->rtnh_hops = nhop[i].hops - 1;

		rtnh = RTNH_NEXT(rtnh);
		i++;
	}

	if (rta->rta_len > RTA_LENGTH(0))
		addattr_l(n, 1024, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
	return 0;
}
コード例 #13
0
ファイル: ipntable.c プロジェクト: eworm-de/iproute2
static int ipntable_modify(int cmd, int flags, int argc, char **argv)
{
	struct {
		struct nlmsghdr	n;
		struct ndtmsg		ndtm;
		char			buf[1024];
	} req = {
		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg)),
		.n.nlmsg_flags = NLM_F_REQUEST | flags,
		.n.nlmsg_type = cmd,
		.ndtm.ndtm_family = preferred_family,
	};
	char *namep = NULL;
	char *threshsp = NULL;
	char *gc_intp = NULL;
	char parms_buf[1024] = {};
	struct rtattr *parms_rta = (struct rtattr *)parms_buf;
	int parms_change = 0;

	parms_rta->rta_type = NDTA_PARMS;
	parms_rta->rta_len = RTA_LENGTH(0);

	while (argc > 0) {
		if (strcmp(*argv, "name") == 0) {
			int len;

			NEXT_ARG();
			if (namep)
				duparg("NAME", *argv);

			namep = *argv;
			len = strlen(namep) + 1;
			addattr_l(&req.n, sizeof(req), NDTA_NAME, namep, len);
		} else if (strcmp(*argv, "thresh1") == 0) {
			__u32 thresh1;

			NEXT_ARG();
			threshsp = *argv;

			if (get_u32(&thresh1, *argv, 0))
				invarg("\"thresh1\" value is invalid", *argv);

			addattr32(&req.n, sizeof(req), NDTA_THRESH1, thresh1);
		} else if (strcmp(*argv, "thresh2") == 0) {
			__u32 thresh2;

			NEXT_ARG();
			threshsp = *argv;

			if (get_u32(&thresh2, *argv, 0))
				invarg("\"thresh2\" value is invalid", *argv);

			addattr32(&req.n, sizeof(req), NDTA_THRESH2, thresh2);
		} else if (strcmp(*argv, "thresh3") == 0) {
			__u32 thresh3;

			NEXT_ARG();
			threshsp = *argv;

			if (get_u32(&thresh3, *argv, 0))
				invarg("\"thresh3\" value is invalid", *argv);

			addattr32(&req.n, sizeof(req), NDTA_THRESH3, thresh3);
		} else if (strcmp(*argv, "gc_int") == 0) {
			__u64 gc_int;

			NEXT_ARG();
			gc_intp = *argv;

			if (get_u64(&gc_int, *argv, 0))
				invarg("\"gc_int\" value is invalid", *argv);

			addattr_l(&req.n, sizeof(req), NDTA_GC_INTERVAL,
				  &gc_int, sizeof(gc_int));
		} else if (strcmp(*argv, "dev") == 0) {
			__u32 ifindex;

			NEXT_ARG();
			ifindex = ll_name_to_index(*argv);
			if (!ifindex)
				return nodev(*argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_IFINDEX, ifindex);
		} else if (strcmp(*argv, "base_reachable") == 0) {
			__u64 breachable;

			NEXT_ARG();

			if (get_u64(&breachable, *argv, 0))
				invarg("\"base_reachable\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_BASE_REACHABLE_TIME,
				      &breachable, sizeof(breachable));
			parms_change = 1;
		} else if (strcmp(*argv, "retrans") == 0) {
			__u64 retrans;

			NEXT_ARG();

			if (get_u64(&retrans, *argv, 0))
				invarg("\"retrans\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_RETRANS_TIME,
				      &retrans, sizeof(retrans));
			parms_change = 1;
		} else if (strcmp(*argv, "gc_stale") == 0) {
			__u64 gc_stale;

			NEXT_ARG();

			if (get_u64(&gc_stale, *argv, 0))
				invarg("\"gc_stale\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_GC_STALETIME,
				      &gc_stale, sizeof(gc_stale));
			parms_change = 1;
		} else if (strcmp(*argv, "delay_probe") == 0) {
			__u64 delay_probe;

			NEXT_ARG();

			if (get_u64(&delay_probe, *argv, 0))
				invarg("\"delay_probe\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_DELAY_PROBE_TIME,
				      &delay_probe, sizeof(delay_probe));
			parms_change = 1;
		} else if (strcmp(*argv, "queue") == 0) {
			__u32 queue;

			NEXT_ARG();

			if (get_u32(&queue, *argv, 0))
				invarg("\"queue\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_QUEUE_LEN, queue);
			parms_change = 1;
		} else if (strcmp(*argv, "app_probes") == 0) {
			__u32 aprobe;

			NEXT_ARG();

			if (get_u32(&aprobe, *argv, 0))
				invarg("\"app_probes\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_APP_PROBES, aprobe);
			parms_change = 1;
		} else if (strcmp(*argv, "ucast_probes") == 0) {
			__u32 uprobe;

			NEXT_ARG();

			if (get_u32(&uprobe, *argv, 0))
				invarg("\"ucast_probes\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_UCAST_PROBES, uprobe);
			parms_change = 1;
		} else if (strcmp(*argv, "mcast_probes") == 0) {
			__u32 mprobe;

			NEXT_ARG();

			if (get_u32(&mprobe, *argv, 0))
				invarg("\"mcast_probes\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_MCAST_PROBES, mprobe);
			parms_change = 1;
		} else if (strcmp(*argv, "anycast_delay") == 0) {
			__u64 anycast_delay;

			NEXT_ARG();

			if (get_u64(&anycast_delay, *argv, 0))
				invarg("\"anycast_delay\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_ANYCAST_DELAY,
				      &anycast_delay, sizeof(anycast_delay));
			parms_change = 1;
		} else if (strcmp(*argv, "proxy_delay") == 0) {
			__u64 proxy_delay;

			NEXT_ARG();

			if (get_u64(&proxy_delay, *argv, 0))
				invarg("\"proxy_delay\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_PROXY_DELAY,
				      &proxy_delay, sizeof(proxy_delay));
			parms_change = 1;
		} else if (strcmp(*argv, "proxy_queue") == 0) {
			__u32 pqueue;

			NEXT_ARG();

			if (get_u32(&pqueue, *argv, 0))
				invarg("\"proxy_queue\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_PROXY_QLEN, pqueue);
			parms_change = 1;
		} else if (strcmp(*argv, "locktime") == 0) {
			__u64 locktime;

			NEXT_ARG();

			if (get_u64(&locktime, *argv, 0))
				invarg("\"locktime\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_LOCKTIME,
				      &locktime, sizeof(locktime));
			parms_change = 1;
		} else {
			invarg("unknown", *argv);
		}

		argc--; argv++;
	}

	if (!namep)
		missarg("NAME");
	if (!threshsp && !gc_intp && !parms_change) {
		fprintf(stderr, "Not enough information: changeable attributes required.\n");
		exit(-1);
	}

	if (parms_rta->rta_len > RTA_LENGTH(0)) {
		addattr_l(&req.n, sizeof(req), NDTA_PARMS, RTA_DATA(parms_rta),
			  RTA_PAYLOAD(parms_rta));
	}

	if (rtnl_talk(&rth, &req.n, NULL) < 0)
		exit(2);

	return 0;
}

static const char *ntable_strtime_delta(__u32 msec)
{
	static char str[32];
	struct timeval now = {};
	time_t t;
	struct tm *tp;

	if (msec == 0)
		goto error;

	if (gettimeofday(&now, NULL) < 0) {
		perror("gettimeofday");
		goto error;
	}

	t = now.tv_sec - (msec / 1000);
	tp = localtime(&t);
	if (!tp)
		goto error;

	strftime(str, sizeof(str), "%Y-%m-%d %T", tp);

	return str;
 error:
	strcpy(str, "(error)");
	return str;
}

static void print_ndtconfig(const struct ndt_config *ndtc)
{

	print_uint(PRINT_ANY, "key_length",
		   "    config key_len %u ", ndtc->ndtc_key_len);
	print_uint(PRINT_ANY, "entry_size",
		   "entry_size %u ", ndtc->ndtc_entry_size);
	print_uint(PRINT_ANY, "entries", "entries %u ", ndtc->ndtc_entries);

	print_nl();

	print_string(PRINT_ANY, "last_flush",
		     "        last_flush %s ",
		     ntable_strtime_delta(ndtc->ndtc_last_flush));
	print_string(PRINT_ANY, "last_rand",
		     "last_rand %s ",
		     ntable_strtime_delta(ndtc->ndtc_last_rand));

	print_nl();

	print_uint(PRINT_ANY, "hash_rnd",
		   "        hash_rnd %u ", ndtc->ndtc_hash_rnd);
	print_0xhex(PRINT_ANY, "hash_mask",
		    "hash_mask %08llx ", ndtc->ndtc_hash_mask);

	print_uint(PRINT_ANY, "hash_chain_gc",
		   "hash_chain_gc %u ", ndtc->ndtc_hash_chain_gc);
	print_uint(PRINT_ANY, "proxy_qlen",
		   "proxy_qlen %u ", ndtc->ndtc_proxy_qlen);

	print_nl();
}
コード例 #14
0
ファイル: netlink.c プロジェクト: dervel/eigrp
int multipath_route_add(struct sockaddr_storage *destination,  vector *gateways,int prefix, unsigned int metric){
	struct rtnl_handle rth;

	// structure of the netlink packet. 
	struct{
		struct nlmsghdr n;
		struct rtmsg r;
		char buf[1024];
	} req;

	memset(&req, 0, sizeof(req));

	// Initialisation of a few parameters 
	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE;
	req.n.nlmsg_type = RTM_NEWROUTE;
	req.r.rtm_family = destination->ss_family;
	req.r.rtm_table = get_eigrp_routing_table_number();
	req.r.rtm_dst_len = prefix;
	req.r.rtm_protocol = get_eigrp_routing_protocol_number();
	req.r.rtm_scope = RT_SCOPE_UNIVERSE;
	req.r.rtm_type = RTN_UNICAST;
	
	// RTA_DST and RTA_GW are the two esential parameters for adding a route
	// for ipv4, the length of the address is 4 bytes.
	if(destination->ss_family == AF_INET){
		struct sockaddr_in *dest = (struct sockaddr_in *)destination;
		addattr_l(&req.n, sizeof(req), RTA_DST, &dest->sin_addr.s_addr, 4);

		addattr_l(&req.n, sizeof(req), RTA_PRIORITY, &metric, 4);

		char buf[NL_PKT_BUF_SIZE];		

		struct rtattr *rta = (void *)buf;
		struct rtnexthop *rtnh;
		
		rta->rta_type = RTA_MULTIPATH;
		rta->rta_len = RTA_LENGTH(0);
		rtnh = RTA_DATA(rta);

		int i;
		for(i=0;i<gateways->size;i++){
			struct sockaddr_in *gate = (struct sockaddr_in *)vector_get(gateways,i);

			rtnh->rtnh_len = sizeof(*rtnh);
			rtnh->rtnh_flags = 0;
			rtnh->rtnh_hops = gate->sin_port; //sockaddr_in.sin_port is used as the weight of the route, -1 is because rta adds plus one by it self
			rta->rta_len += rtnh->rtnh_len;

			char address[INET6_ADDRSTRLEN];
			ip_tochar(&address,vector_get(gateways,i));
			printf("Route through %s weight %d\n",address,rtnh->rtnh_hops);

			rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, &gate->sin_addr.s_addr, 4);
			rtnh->rtnh_len += (sizeof(struct rtattr) + 4);

			rtnh = RTNH_NEXT(rtnh);
		}
		addattr_l(&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
	}
	
	//addattr_l(&req.n, sizeof(req), RTA_PRIORITY, metric, 4);

	int status = 0;

	// opening the netlink socket to communicate with the kernel
	if (rtnl_open(&rth, 0) < 0){
		printf("cannot open rtnetlink\n");
		return -1;
	}

	// sending the packet to the kernel.
	status = rtnl_talk(&rth, &req.n, 0, 0, NULL);
	if (status < 0)
		return status;
	
	rtnl_close(&rth);
	return 0;
}