static void add_nexthop(nexthop_t *nh, struct nlmsghdr *nlh, struct rtmsg *rtm, struct rtattr *rta, size_t len, struct rtnexthop *rtnh) { if (nh->addr) { if (rtm->rtm_family == nh->addr->ifa.ifa_family) rtnh->rtnh_len += add_addr2rta(rta, len, RTA_GATEWAY, nh->addr); #ifdef _HAVE_RTA_VIA_ else rtnh->rtnh_len += add_addrfam2rta(rta, len, RTA_VIA, nh->addr); #endif } if (nh->ifp) rtnh->rtnh_ifindex = nh->ifp->ifindex; if (nh->mask |= IPROUTE_BIT_WEIGHT) rtnh->rtnh_hops = nh->weight; rtnh->rtnh_flags = nh->flags; if (nh->realms) rtnh->rtnh_len += rta_addattr32(rta, len, RTA_FLOW, nh->realms); #ifdef _HAVE_RTA_ENCAP_ if (nh->encap.type != LWTUNNEL_ENCAP_NONE) { int len = rta->rta_len; add_encap(rta, len, &nh->encap); rtnh->rtnh_len += rta->rta_len - len; } #endif }
int parse_one_nh(struct rtattr *rta, struct rtnexthop *rtnh, int *argcp, char *argvp) { int argc = *argcp; char *argv = argvp; while(++argv, --argc > 0) { if(strcmp(argv, "via") == 0) { NEXT_ARG(); rta_addattr32(rta, 4096, RTA_GATEWAY, get_addr32(argv)); rtnh->rtnh_len += sizeof(struct rtattr) + 4; } else if(strcmp(argv, "dev") == 0) { NEXT_ARG(); if((rtnh->rtnh_ifindex = ll_name_to_index(argv)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", argv); exit(1); } } else if(strcmp(argv, "weight") == 0) { unsigned w; NEXT_ARG(); if(get_unsigned(&w, argv, 0) || w == 0 || w > 256) { invarg("\"weight\" is invalid\n", argv); } rtnh->rtnh_hops = w - 1; } else if(strcmp(argv, "onlink") == 0) { rtnh->rtnh_flags |= RTNH_F_ONLINK; } else break; } *argcp = argc; argvp = argv; return 0; }
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; }
/* 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; }
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; }
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(); }
static int iproute_modify(int cmd, unsigned flags, int argc, char **argv) { struct rtnl_handle rth; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; char mxbuf[256]; struct rtattr * mxrta = (void*)mxbuf; unsigned mxlock = 0; char *d = NULL; int gw_ok = 0; int dst_ok = 0; int proto_ok = 0; int type_ok = 0; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.r.rtm_family = preferred_family; req.r.rtm_table = RT_TABLE_MAIN; req.r.rtm_scope = RT_SCOPE_NOWHERE; if (cmd != RTM_DELROUTE) { req.r.rtm_protocol = RTPROT_BOOT; req.r.rtm_scope = RT_SCOPE_UNIVERSE; req.r.rtm_type = RTN_UNICAST; } mxrta->rta_type = RTA_METRICS; mxrta->rta_len = RTA_LENGTH(0); while (argc > 0) { if (strcmp(*argv, "src") == 0) { inet_prefix addr; NEXT_ARG(); get_addr(&addr, *argv, req.r.rtm_family); if (req.r.rtm_family == AF_UNSPEC) { req.r.rtm_family = addr.family; } addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen); } else if (strcmp(*argv, "via") == 0) { inet_prefix addr; gw_ok = 1; NEXT_ARG(); get_addr(&addr, *argv, req.r.rtm_family); if (req.r.rtm_family == AF_UNSPEC) { req.r.rtm_family = addr.family; } addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen); } else if (strcmp(*argv, "mtu") == 0) { unsigned mtu; NEXT_ARG(); if (strcmp(*argv, "lock") == 0) { mxlock |= (1<<RTAX_MTU); NEXT_ARG(); } if (get_unsigned(&mtu, *argv, 0)) { invarg("\"mtu\" value is invalid\n", *argv); } rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu); } else if (matches(*argv, "protocol") == 0) { int prot; NEXT_ARG(); if (rtnl_rtprot_a2n(&prot, *argv)) invarg("\"protocol\" value is invalid\n", *argv); req.r.rtm_protocol = prot; proto_ok =1; } else if (strcmp(*argv, "dev") == 0 || strcmp(*argv, "oif") == 0) { NEXT_ARG(); d = *argv; } else { int type; inet_prefix dst; if (strcmp(*argv, "to") == 0) { NEXT_ARG(); } if ((**argv < '0' || **argv > '9') && rtnl_rtntype_a2n(&type, *argv) == 0) { NEXT_ARG(); req.r.rtm_type = type; type_ok = 1; } if (dst_ok) { duparg2("to", *argv); } get_prefix(&dst, *argv, req.r.rtm_family); if (req.r.rtm_family == AF_UNSPEC) { req.r.rtm_family = dst.family; } req.r.rtm_dst_len = dst.bitlen; dst_ok = 1; if (dst.bytelen) { addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen); } } argc--; argv++; } if (rtnl_open(&rth, 0) < 0) { exit(1); } if (d) { int idx; ll_init_map(&rth); if (d) { if ((idx = ll_name_to_index(d)) == 0) { bb_error_msg("Cannot find device \"%s\"", d); return -1; } addattr32(&req.n, sizeof(req), RTA_OIF, idx); } } if (mxrta->rta_len > RTA_LENGTH(0)) { if (mxlock) { rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock); } addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta)); } if (req.r.rtm_family == AF_UNSPEC) { req.r.rtm_family = AF_INET; } if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) { exit(2); } return 0; }
int iproute_modify(int cmd, unsigned flags, int argc, char *argv) { REQ req; char mxbuf[256]; struct rtattr * mxrta = (void*)mxbuf; unsigned mxlock = 0; char *d = NULL; int gw_ok = 0; int dst_ok = 0; int nhs_ok = 0; int scope_ok = 0; int table_ok = 0; // int type_ok = 0; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.r.rtm_family = preferred_family; req.r.rtm_table = RT_TABLE_MAIN; req.r.rtm_scope = RT_SCOPE_NOWHERE; if(cmd != RTM_DELROUTE) { req.r.rtm_protocol = RTPROT_BOOT; req.r.rtm_scope = RT_SCOPE_UNIVERSE; req.r.rtm_type = RTN_UNICAST; } mxrta->rta_type = RTA_METRICS; mxrta->rta_len = RTA_LENGTH(0); while (argc > 0) { if(strcmp(argv, "src") == 0) { inet_prefix addr; NEXT_ARG(); get_addr(&addr, argv, req.r.rtm_family); if(req.r.rtm_family == AF_UNSPEC) req.r.rtm_family = addr.family; addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen); } else if(strcmp(argv, "via") == 0) { inet_prefix addr; gw_ok = 1; NEXT_ARG(); get_addr(&addr, argv, req.r.rtm_family); if(req.r.rtm_family == AF_UNSPEC) req.r.rtm_family = addr.family; addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen); } else if(strcmp(argv, "from") == 0) { inet_prefix addr; NEXT_ARG(); get_prefix(&addr, argv, req.r.rtm_family); if(req.r.rtm_family == AF_UNSPEC) req.r.rtm_family = addr.family; if(addr.bytelen) addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen); req.r.rtm_src_len = addr.bitlen; } else if(strcmp(argv, "tos") == 0 || matches(argv, "dsfield") == 0) { __u32 tos; NEXT_ARG(); if(rtnl_dsfield_a2n(&tos, argv)) invarg("\"tos\" value is invalid\n", argv); req.r.rtm_tos = tos; } else if(matches(argv, "metric") == 0 || matches(argv, "priority") == 0 || matches(argv, "preference") == 0) { __u32 metric; NEXT_ARG(); if(get_u32(&metric, argv, 0)) invarg("\"metric\" value is invalid\n", argv); addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric); } else if(strcmp(argv, "scope") == 0) { __u32 scope = 0; NEXT_ARG(); if(rtnl_rtscope_a2n(&scope, argv)) invarg("invalid \"scope\" value\n", argv); req.r.rtm_scope = scope; scope_ok = 1; } else if(strcmp(argv, "mtu") == 0) { unsigned mtu; NEXT_ARG(); if(strcmp(argv, "lock") == 0) { mxlock |= (1<<RTAX_MTU); NEXT_ARG(); } if(get_unsigned(&mtu, argv, 0)) invarg("\"mtu\" value is invalid\n", argv); rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu); #ifdef RTAX_ADVMSS } else if(strcmp(argv, "advmss") == 0) { unsigned mss; NEXT_ARG(); if(strcmp(argv, "lock") == 0) { mxlock |= (1<<RTAX_ADVMSS); NEXT_ARG(); } if(get_unsigned(&mss, argv, 0)) invarg("\"mss\" value is invalid\n", argv); rta_addattr32(mxrta, sizeof(mxbuf), RTAX_ADVMSS, mss); #endif #ifdef RTAX_REORDERING } else if(matches(argv, "reordering") == 0) { unsigned reord; NEXT_ARG(); if(strcmp(argv, "lock") == 0) { mxlock |= (1<<RTAX_REORDERING); NEXT_ARG(); } if(get_unsigned(&reord, argv, 0)) invarg("\"reordering\" value is invalid\n", argv); rta_addattr32(mxrta, sizeof(mxbuf), RTAX_REORDERING, reord); #endif } else if(strcmp(argv, "rtt") == 0) { unsigned rtt; NEXT_ARG(); if(strcmp(argv, "lock") == 0) { mxlock |= (1<<RTAX_RTT); NEXT_ARG(); } if(get_unsigned(&rtt, argv, 0)) invarg("\"rtt\" value is invalid\n", argv); rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT, rtt); } else if(matches(argv, "window") == 0) { unsigned win; NEXT_ARG(); if(strcmp(argv, "lock") == 0) { mxlock |= (1<<RTAX_WINDOW); NEXT_ARG(); } if(get_unsigned(&win, argv, 0)) invarg("\"window\" value is invalid\n", argv); rta_addattr32(mxrta, sizeof(mxbuf), RTAX_WINDOW, win); } else if(matches(argv, "cwnd") == 0) { unsigned win; NEXT_ARG(); if(strcmp(argv, "lock") == 0) { mxlock |= (1<<RTAX_CWND); NEXT_ARG(); } if(get_unsigned(&win, argv, 0)) invarg("\"cwnd\" value is invalid\n", argv); rta_addattr32(mxrta, sizeof(mxbuf), RTAX_CWND, win); } else if(matches(argv, "rttvar") == 0) { unsigned win; NEXT_ARG(); if(strcmp(argv, "lock") == 0) { mxlock |= (1<<RTAX_RTTVAR); NEXT_ARG(); } if(get_unsigned(&win, argv, 0)) invarg("\"rttvar\" value is invalid\n", argv); rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTTVAR, win); } else if(matches(argv, "ssthresh") == 0) { unsigned win; NEXT_ARG(); if(strcmp(argv, "lock") == 0) { mxlock |= (1<<RTAX_SSTHRESH); NEXT_ARG(); } if(get_unsigned(&win, argv, 0)) invarg("\"ssthresh\" value is invalid\n", argv); rta_addattr32(mxrta, sizeof(mxbuf), RTAX_SSTHRESH, win); // } else if(matches(argv, "realms") == 0) { // __u32 realm; // NEXT_ARG(); // if(get_rt_realms(&realm, argv)) // invarg("\"realm\" value is invalid\n", argv); // addattr32(&req.n, sizeof(req), RTA_FLOW, realm); } else if(strcmp(argv, "onlink") == 0) { req.r.rtm_flags |= RTNH_F_ONLINK; } else if(matches(argv, "equalize") == 0 || strcmp(argv, "eql") == 0) { req.r.rtm_flags |= RTM_F_EQUALIZE; } else if(strcmp(argv, "nexthop") == 0) { nhs_ok = 1; break; } else if(matches(argv, "protocol") == 0) { __u32 prot; NEXT_ARG(); if(rtnl_rtprot_a2n(&prot, argv)) invarg("\"protocol\" value is invalid\n", argv); req.r.rtm_protocol = prot; } else if(matches(argv, "table") == 0) { __u32 tid; NEXT_ARG(); if(rtnl_rttable_a2n(&tid, argv)) invarg("\"table\" value is invalid\n", argv); req.r.rtm_table = tid; table_ok = 1; } else if(strcmp(argv, "dev") == 0 || strcmp(argv, "oif") == 0) { NEXT_ARG(); d = argv; // } else if(strcmp(argv, "mpath") == 0 || // strcmp(argv, "mp") == 0) { // int i; // __u32 mp_alg = IP_MP_ALG_NONE; // // NEXT_ARG(); // for (i = 1; i < ARRAY_SIZE(mp_alg_names); i++) // if(strcmp(argv, mp_alg_names[i]) == 0) // mp_alg = i; // if(mp_alg == IP_MP_ALG_NONE) // invarg("\"mpath\" value is invalid\n", argv); // addattr_l(&req.n, sizeof(req), RTA_MP_ALGO, &mp_alg, sizeof(mp_alg)); } else { // int type; inet_prefix dst; if(strcmp(argv, "to") == 0) { NEXT_ARG(); } // if((*argv < '0' || *argv > '9') && // rtnl_rtntype_a2n(&type, argv) == 0) { // NEXT_ARG(); // req.r.rtm_type = type; // type_ok = 1; // } if(dst_ok) duparg2("to", argv); get_prefix(&dst, argv, req.r.rtm_family); if(req.r.rtm_family == AF_UNSPEC) req.r.rtm_family = dst.family; req.r.rtm_dst_len = dst.bitlen; dst_ok = 1; if(dst.bytelen) addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen); } argc--; argv++; } if(d || nhs_ok) { int idx; ll_init_map(&rth); if(d) { if((idx = ll_name_to_index(d)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return -1; } addattr32(&req.n, sizeof(req), RTA_OIF, idx); } } if(mxrta->rta_len > RTA_LENGTH(0)) { if(mxlock) rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock); addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta)); } if(nhs_ok) parse_nexthops(&req.n, &req.r, argc, argv); if(!table_ok) { if(req.r.rtm_type == RTN_LOCAL || req.r.rtm_type == RTN_BROADCAST || req.r.rtm_type == RTN_NAT || req.r.rtm_type == RTN_ANYCAST) req.r.rtm_table = RT_TABLE_LOCAL; } if(!scope_ok) { if(req.r.rtm_type == RTN_LOCAL || req.r.rtm_type == RTN_NAT) req.r.rtm_scope = RT_SCOPE_HOST; else if(req.r.rtm_type == RTN_BROADCAST || req.r.rtm_type == RTN_MULTICAST || req.r.rtm_type == RTN_ANYCAST) req.r.rtm_scope = RT_SCOPE_LINK; else if(req.r.rtm_type == RTN_UNICAST || req.r.rtm_type == RTN_UNSPEC) { if(cmd == RTM_DELROUTE) req.r.rtm_scope = RT_SCOPE_NOWHERE; else if(!gw_ok && !nhs_ok) req.r.rtm_scope = RT_SCOPE_LINK; } } if(req.r.rtm_family == AF_UNSPEC) req.r.rtm_family = AF_INET; if(rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) exit(2); return 0; }