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; }
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: 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) < 0) exit(2); return 0; }
static int mdb_modify(int cmd, int flags, int argc, char **argv) { struct { struct nlmsghdr n; struct br_port_msg bpm; char buf[1024]; } req; struct br_mdb_entry entry; char *d = NULL, *p = NULL, *grp = NULL; memset(&req, 0, sizeof(req)); memset(&entry, 0, sizeof(entry)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.bpm.family = PF_BRIDGE; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); d = *argv; } else if (strcmp(*argv, "grp") == 0) { NEXT_ARG(); grp = *argv; } else if (strcmp(*argv, "port") == 0) { NEXT_ARG(); p = *argv; } else if (strcmp(*argv, "permanent") == 0) { if (cmd == RTM_NEWMDB) entry.state |= MDB_PERMANENT; } else if (strcmp(*argv, "temp") == 0) { ;/* nothing */ } else { if (matches(*argv, "help") == 0) usage(); } argc--; argv++; } if (d == NULL || grp == NULL || p == NULL) { fprintf(stderr, "Device, group address and port name are required arguments.\n"); exit(-1); } req.bpm.ifindex = ll_name_to_index(d); if (req.bpm.ifindex == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return -1; } entry.ifindex = ll_name_to_index(p); if (entry.ifindex == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", p); return -1; } if (!inet_pton(AF_INET, grp, &entry.addr.u.ip4)) { if (!inet_pton(AF_INET6, grp, &entry.addr.u.ip6)) { fprintf(stderr, "Invalid address \"%s\"\n", grp); return -1; } else entry.addr.proto = htons(ETH_P_IPV6); } else entry.addr.proto = htons(ETH_P_IP); addattr_l(&req.n, sizeof(req), MDBA_SET_ENTRY, &entry, sizeof(entry)); if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) exit(2); return 0; }
static int ipaddr_modify(int cmd, int argc, char **argv) { static const char *const option[] = { "peer", "remote", "broadcast", "brd", "anycast", "scope", "dev", "label", "local", 0 }; struct rtnl_handle rth; struct { struct nlmsghdr n; struct ifaddrmsg ifa; char buf[256]; } req; char *d = NULL; char *l = NULL; inet_prefix lcl; inet_prefix peer; int local_len = 0; int peer_len = 0; int brd_len = 0; int any_len = 0; int scoped = 0; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = cmd; req.ifa.ifa_family = preferred_family; while (argc > 0) { const int option_num = index_in_str_array(option, *argv); switch (option_num) { case 0: /* peer */ case 1: /* remote */ NEXT_ARG(); if (peer_len) { duparg("peer", *argv); } get_prefix(&peer, *argv, req.ifa.ifa_family); peer_len = peer.bytelen; if (req.ifa.ifa_family == AF_UNSPEC) { req.ifa.ifa_family = peer.family; } addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen); req.ifa.ifa_prefixlen = peer.bitlen; break; case 2: /* broadcast */ case 3: /* brd */ { inet_prefix addr; NEXT_ARG(); if (brd_len) { duparg("broadcast", *argv); } if (LONE_CHAR(*argv, '+')) { brd_len = -1; } else if (LONE_DASH(*argv)) { brd_len = -2; } else { get_addr(&addr, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) req.ifa.ifa_family = addr.family; addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen); brd_len = addr.bytelen; } break; } case 4: /* anycast */ { inet_prefix addr; NEXT_ARG(); if (any_len) { duparg("anycast", *argv); } get_addr(&addr, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) { req.ifa.ifa_family = addr.family; } addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen); any_len = addr.bytelen; break; } case 5: /* scope */ { uint32_t scope = 0; NEXT_ARG(); if (rtnl_rtscope_a2n(&scope, *argv)) { invarg(*argv, "scope"); } req.ifa.ifa_scope = scope; scoped = 1; break; } case 6: /* dev */ NEXT_ARG(); d = *argv; break; case 7: /* label */ NEXT_ARG(); l = *argv; addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1); break; case 8: /* local */ NEXT_ARG(); default: if (local_len) { duparg2("local", *argv); } get_prefix(&lcl, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) { req.ifa.ifa_family = lcl.family; } addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen); local_len = lcl.bytelen; } argc--; argv++; } if (d == NULL) { bb_error_msg(bb_msg_requires_arg,"\"dev\""); return -1; } if (l && matches(d, l) != 0) { bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d, l); } if (peer_len == 0 && local_len && cmd != RTM_DELADDR) { peer = lcl; addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen); } if (req.ifa.ifa_prefixlen == 0) req.ifa.ifa_prefixlen = lcl.bitlen; if (brd_len < 0 && cmd != RTM_DELADDR) { inet_prefix brd; int i; if (req.ifa.ifa_family != AF_INET) { bb_error_msg("broadcast can be set only for IPv4 addresses"); return -1; } brd = peer; if (brd.bitlen <= 30) { for (i=31; i>=brd.bitlen; i--) { if (brd_len == -1) brd.data[0] |= htonl(1<<(31-i)); else brd.data[0] &= ~htonl(1<<(31-i)); } addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen); brd_len = brd.bytelen; } } if (!scoped && cmd != RTM_DELADDR) req.ifa.ifa_scope = default_scope(&lcl); if (rtnl_open(&rth, 0) < 0) exit(1); ll_init_map(&rth); if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) { bb_error_msg("cannot find device \"%s\"", d); return -1; } if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) exit(2); exit(0); }
static int ipaddrlabel_modify(int cmd, int argc, char **argv) { struct { struct nlmsghdr n; struct ifaddrlblmsg ifal; char buf[1024]; } req; inet_prefix prefix; uint32_t label = 0xffffffffUL; char *p = NULL; char *l = NULL; memset(&req, 0, sizeof(req)); memset(&prefix, 0, sizeof(prefix)); req.n.nlmsg_type = cmd; req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.ifal.ifal_family = preferred_family; req.ifal.ifal_prefixlen = 0; req.ifal.ifal_index = 0; if (cmd == RTM_NEWADDRLABEL) { req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; } while (argc > 0) { if (strcmp(*argv, "prefix") == 0) { NEXT_ARG(); p = *argv; get_prefix(&prefix, *argv, preferred_family); } else if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); if ((req.ifal.ifal_index = ll_name_to_index(*argv)) == 0) invarg("dev is invalid\n", *argv); } else if (strcmp(*argv, "label") == 0) { NEXT_ARG(); l = *argv; if (get_u32(&label, *argv, 0) || label == 0xffffffffUL) invarg("label is invalid\n", *argv); } argc--; argv++; } if (p == NULL) { fprintf(stderr, "Not enough information: \"prefix\" argument is required.\n"); return -1; } if (l == NULL) { fprintf(stderr, "Not enough information: \"label\" argument is required.\n"); return -1; } addattr32(&req.n, sizeof(req), IFAL_LABEL, label); addattr_l(&req.n, sizeof(req), IFAL_ADDRESS, &prefix.data, prefix.bytelen); req.ifal.ifal_prefixlen = prefix.bitlen; if (req.ifal.ifal_family == AF_UNSPEC) req.ifal.ifal_family = AF_INET6; if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) return 2; return 0; }
static int ipneigh_modify(int cmd, int flags, int argc, char **argv) { struct { struct nlmsghdr n; struct ndmsg ndm; char buf[256]; } req; char *d = NULL; int dst_ok = 0; int lladdr_ok = 0; char * lla = NULL; inet_prefix dst; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.ndm.ndm_family = preferred_family; req.ndm.ndm_state = NUD_PERMANENT; while (argc > 0) { if (matches(*argv, "lladdr") == 0) { NEXT_ARG(); if (lladdr_ok) duparg("lladdr", *argv); lla = *argv; lladdr_ok = 1; } else if (strcmp(*argv, "nud") == 0) { unsigned state; NEXT_ARG(); if (nud_state_a2n(&state, *argv)) invarg("nud state is bad", *argv); req.ndm.ndm_state = state; } else if (matches(*argv, "proxy") == 0) { NEXT_ARG(); if (matches(*argv, "help") == 0) usage(); if (dst_ok) duparg("address", *argv); get_addr(&dst, *argv, preferred_family); dst_ok = 1; req.ndm.ndm_flags |= NTF_PROXY; } else if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); d = *argv; } else { if (strcmp(*argv, "to") == 0) { NEXT_ARG(); } if (matches(*argv, "help") == 0) { NEXT_ARG(); } if (dst_ok) duparg2("to", *argv); get_addr(&dst, *argv, preferred_family); dst_ok = 1; } argc--; argv++; } if (d == NULL || !dst_ok || dst.family == AF_UNSPEC) { fprintf(stderr, "Device and destination are required arguments.\n"); exit(-1); } req.ndm.ndm_family = dst.family; if (addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen) < 0) return -1; if (lla && strcmp(lla, "null")) { char llabuf[20]; int l; l = ll_addr_a2n(llabuf, sizeof(llabuf), lla); if (l < 0) return -1; if (addattr_l(&req.n, sizeof(req), NDA_LLADDR, llabuf, l) < 0) return -1; } ll_init_map(&rth); if ((req.ndm.ndm_ifindex = ll_name_to_index(d)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return -1; } if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) exit(2); return 0; }
int ipaddr_modify(int cmd, int argc, char **argv) { struct rtnl_handle rth; struct { struct nlmsghdr n; struct ifaddrmsg ifa; char buf[256]; } req; char *d = NULL; char *l = NULL; char *lcl_arg = NULL; inet_prefix lcl; inet_prefix peer; int local_len = 0; int peer_len = 0; int brd_len = 0; int any_len = 0; int scoped = 0; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = cmd; req.ifa.ifa_family = preferred_family; while (argc > 0) { if (strcmp(*argv, "peer") == 0 || strcmp(*argv, "remote") == 0) { NEXT_ARG(); if (peer_len) duparg("peer", *argv); get_prefix(&peer, *argv, req.ifa.ifa_family); peer_len = peer.bytelen; if (req.ifa.ifa_family == AF_UNSPEC) req.ifa.ifa_family = peer.family; addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen); req.ifa.ifa_prefixlen = peer.bitlen; } else if (matches(*argv, "broadcast") == 0 || strcmp(*argv, "brd") == 0) { inet_prefix addr; NEXT_ARG(); if (brd_len) duparg("broadcast", *argv); if (strcmp(*argv, "+") == 0) brd_len = -1; else if (strcmp(*argv, "-") == 0) brd_len = -2; else { get_addr(&addr, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) req.ifa.ifa_family = addr.family; addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen); brd_len = addr.bytelen; } } else if (strcmp(*argv, "anycast") == 0) { inet_prefix addr; NEXT_ARG(); if (any_len) duparg("anycast", *argv); get_addr(&addr, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) req.ifa.ifa_family = addr.family; addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen); any_len = addr.bytelen; } else if (strcmp(*argv, "scope") == 0) { int scope = 0; NEXT_ARG(); if (rtnl_rtscope_a2n(&scope, *argv)) invarg(*argv, "invalid scope value."); req.ifa.ifa_scope = scope; scoped = 1; } else if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); d = *argv; } else if (strcmp(*argv, "label") == 0) { NEXT_ARG(); l = *argv; addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1); } else { if (strcmp(*argv, "local") == 0) { NEXT_ARG(); } if (matches(*argv, "help") == 0) usage(); if (local_len) duparg2("local", *argv); lcl_arg = *argv; get_prefix(&lcl, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) req.ifa.ifa_family = lcl.family; addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen); local_len = lcl.bytelen; } argc--; argv++; } if (d == NULL) { fprintf(stderr, "Not enough information: \"dev\" argument is required.\n"); return -1; } if (l && matches(d, l) != 0) { fprintf(stderr, "\"dev\" (%s) must match \"label\" (%s).\n", d, l); exit(1); } if (peer_len == 0 && local_len) { if (cmd == RTM_DELADDR && lcl.family == AF_INET && !(lcl.flags & PREFIXLEN_SPECIFIED)) { fprintf(stderr, "Warning: Executing wildcard deletion to stay compatible with old scripts.\n" \ " Explicitly specify the prefix length (%s/%d) to avoid this warning.\n" \ " This special behaviour is likely to disappear in further releases,\n" \ " fix your scripts!\n", lcl_arg, local_len*8); } else { peer = lcl; addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen); } } if (req.ifa.ifa_prefixlen == 0) req.ifa.ifa_prefixlen = lcl.bitlen; if (brd_len < 0 && cmd != RTM_DELADDR) { inet_prefix brd; int i; if (req.ifa.ifa_family != AF_INET) { fprintf(stderr, "Broadcast can be set only for IPv4 addresses\n"); return -1; } brd = peer; if (brd.bitlen <= 30) { for (i=31; i>=brd.bitlen; i--) { if (brd_len == -1) brd.data[0] |= htonl(1<<(31-i)); else brd.data[0] &= ~htonl(1<<(31-i)); } addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen); brd_len = brd.bytelen; } } if (!scoped && cmd != RTM_DELADDR) req.ifa.ifa_scope = default_scope(&lcl); if (rtnl_open(&rth, 0) < 0) exit(1); ll_init_map(&rth); if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return -1; } if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) exit(2); exit(0); }
static int do_tunnels_list(struct ip_tunnel_parm *p) { char buf[512]; int err = -1; FILE *fp = fopen("/proc/net/dev", "r"); if (fp == NULL) { perror("fopen"); return -1; } /* skip header lines */ if (!fgets(buf, sizeof(buf), fp) || !fgets(buf, sizeof(buf), fp)) { fprintf(stderr, "/proc/net/dev read error\n"); goto end; } while (fgets(buf, sizeof(buf), fp) != NULL) { char name[IFNAMSIZ]; int index, type; struct ip_tunnel_parm p1; char *ptr; buf[sizeof(buf) - 1] = 0; ptr = strchr(buf, ':'); if (ptr == NULL || (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) { fprintf(stderr, "Wrong format for /proc/net/dev. Giving up.\n"); goto end; } if (p->name[0] && strcmp(p->name, name)) continue; index = ll_name_to_index(name); if (index == 0) continue; type = ll_index_to_type(index); if (type == -1) { fprintf(stderr, "Failed to get type of \"%s\"\n", name); continue; } if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT) continue; memset(&p1, 0, sizeof(p1)); if (tnl_get_ioctl(name, &p1)) continue; if ((p->link && p1.link != p->link) || (p->name[0] && strcmp(p1.name, p->name)) || (p->iph.daddr && p1.iph.daddr != p->iph.daddr) || (p->iph.saddr && p1.iph.saddr != p->iph.saddr) || (p->i_key && p1.i_key != p->i_key)) continue; print_tunnel(&p1); if (show_stats) tnl_print_stats(ptr); printf("\n"); } err = 0; end: fclose(fp); return err; }
static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) { int count = 0; char medium[IFNAMSIZ]; int isatap = 0; memset(p, 0, sizeof(*p)); memset(&medium, 0, sizeof(medium)); p->iph.version = 4; p->iph.ihl = 5; #ifndef IP_DF #define IP_DF 0x4000 /* Flag: "Don't Fragment" */ #endif p->iph.frag_off = htons(IP_DF); while (argc > 0) { if (strcmp(*argv, "mode") == 0) { NEXT_ARG(); if (strcmp(*argv, "ipip") == 0 || strcmp(*argv, "ip/ip") == 0) { set_tunnel_proto(p, IPPROTO_IPIP); } else if (strcmp(*argv, "gre") == 0 || strcmp(*argv, "gre/ip") == 0) { set_tunnel_proto(p, IPPROTO_GRE); } else if (strcmp(*argv, "sit") == 0 || strcmp(*argv, "ipv6/ip") == 0) { set_tunnel_proto(p, IPPROTO_IPV6); } else if (strcmp(*argv, "isatap") == 0) { set_tunnel_proto(p, IPPROTO_IPV6); isatap++; } else if (strcmp(*argv, "vti") == 0) { set_tunnel_proto(p, IPPROTO_IPIP); p->i_flags |= VTI_ISVTI; } else { fprintf(stderr, "Unknown tunnel mode \"%s\"\n", *argv); exit(-1); } } else if (strcmp(*argv, "key") == 0) { NEXT_ARG(); p->i_flags |= GRE_KEY; p->o_flags |= GRE_KEY; p->i_key = p->o_key = tnl_parse_key("key", *argv); } else if (strcmp(*argv, "ikey") == 0) { NEXT_ARG(); p->i_flags |= GRE_KEY; p->i_key = tnl_parse_key("ikey", *argv); } else if (strcmp(*argv, "okey") == 0) { NEXT_ARG(); p->o_flags |= GRE_KEY; p->o_key = tnl_parse_key("okey", *argv); } else if (strcmp(*argv, "seq") == 0) { p->i_flags |= GRE_SEQ; p->o_flags |= GRE_SEQ; } else if (strcmp(*argv, "iseq") == 0) { p->i_flags |= GRE_SEQ; } else if (strcmp(*argv, "oseq") == 0) { p->o_flags |= GRE_SEQ; } else if (strcmp(*argv, "csum") == 0) { p->i_flags |= GRE_CSUM; p->o_flags |= GRE_CSUM; } else if (strcmp(*argv, "icsum") == 0) { p->i_flags |= GRE_CSUM; } else if (strcmp(*argv, "ocsum") == 0) { p->o_flags |= GRE_CSUM; } else if (strcmp(*argv, "nopmtudisc") == 0) { p->iph.frag_off = 0; } else if (strcmp(*argv, "pmtudisc") == 0) { p->iph.frag_off = htons(IP_DF); } else if (strcmp(*argv, "remote") == 0) { NEXT_ARG(); if (strcmp(*argv, "any")) p->iph.daddr = get_addr32(*argv); else p->iph.daddr = htonl(INADDR_ANY); } else if (strcmp(*argv, "local") == 0) { NEXT_ARG(); if (strcmp(*argv, "any")) p->iph.saddr = get_addr32(*argv); else p->iph.saddr = htonl(INADDR_ANY); } else if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); strncpy(medium, *argv, IFNAMSIZ - 1); } else if (strcmp(*argv, "ttl") == 0 || strcmp(*argv, "hoplimit") == 0 || strcmp(*argv, "hlim") == 0) { __u8 uval; NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) { if (get_u8(&uval, *argv, 0)) invarg("invalid TTL\n", *argv); p->iph.ttl = uval; } } else if (strcmp(*argv, "tos") == 0 || strcmp(*argv, "tclass") == 0 || matches(*argv, "dsfield") == 0) { char *dsfield; __u32 uval; NEXT_ARG(); dsfield = *argv; strsep(&dsfield, "/"); if (strcmp(*argv, "inherit") != 0) { dsfield = *argv; p->iph.tos = 0; } else p->iph.tos = 1; if (dsfield) { if (rtnl_dsfield_a2n(&uval, dsfield)) invarg("bad TOS value", *argv); p->iph.tos |= uval; } } else { if (strcmp(*argv, "name") == 0) NEXT_ARG(); else if (matches(*argv, "help") == 0) usage(); if (p->name[0]) duparg2("name", *argv); strncpy(p->name, *argv, IFNAMSIZ - 1); if (cmd == SIOCCHGTUNNEL && count == 0) { struct ip_tunnel_parm old_p; memset(&old_p, 0, sizeof(old_p)); if (tnl_get_ioctl(*argv, &old_p)) return -1; *p = old_p; } } count++; argc--; argv++; } if (p->iph.protocol == 0) { if (memcmp(p->name, "gre", 3) == 0) p->iph.protocol = IPPROTO_GRE; else if (memcmp(p->name, "ipip", 4) == 0) p->iph.protocol = IPPROTO_IPIP; else if (memcmp(p->name, "sit", 3) == 0) p->iph.protocol = IPPROTO_IPV6; else if (memcmp(p->name, "isatap", 6) == 0) { p->iph.protocol = IPPROTO_IPV6; isatap++; } else if (memcmp(p->name, "vti", 3) == 0) { p->iph.protocol = IPPROTO_IPIP; p->i_flags |= VTI_ISVTI; } } if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) { if (!(p->i_flags & VTI_ISVTI) && (p->iph.protocol != IPPROTO_GRE)) { fprintf(stderr, "Keys are not allowed with ipip and sit tunnels\n"); return -1; } } if (medium[0]) { p->link = ll_name_to_index(medium); if (p->link == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", medium); return -1; } } if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) { p->i_key = p->iph.daddr; p->i_flags |= GRE_KEY; } if (p->o_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) { p->o_key = p->iph.daddr; p->o_flags |= GRE_KEY; } if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) { fprintf(stderr, "A broadcast tunnel requires a source address\n"); return -1; } if (isatap) p->i_flags |= SIT_ISATAP; return 0; }
static int ipaddrlabel_modify(int cmd, int argc, char **argv) { struct { struct nlmsghdr n; struct ifaddrlblmsg ifal; char buf[1024]; } req = { .n.nlmsg_type = cmd, .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg)), .n.nlmsg_flags = NLM_F_REQUEST, .ifal.ifal_family = preferred_family, }; inet_prefix prefix = {}; uint32_t label = 0xffffffffUL; char *p = NULL; char *l = NULL; if (cmd == RTM_NEWADDRLABEL) { req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; } while (argc > 0) { if (strcmp(*argv, "prefix") == 0) { NEXT_ARG(); p = *argv; get_prefix(&prefix, *argv, preferred_family); } else if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); if ((req.ifal.ifal_index = ll_name_to_index(*argv)) == 0) invarg("dev is invalid\n", *argv); } else if (strcmp(*argv, "label") == 0) { NEXT_ARG(); l = *argv; if (get_u32(&label, *argv, 0) || label == 0xffffffffUL) invarg("label is invalid\n", *argv); } argc--; argv++; } if (p == NULL) { fprintf(stderr, "Not enough information: \"prefix\" argument is required.\n"); return -1; } if (l == NULL) { fprintf(stderr, "Not enough information: \"label\" argument is required.\n"); return -1; } addattr32(&req.n, sizeof(req), IFAL_LABEL, label); addattr_l(&req.n, sizeof(req), IFAL_ADDRESS, &prefix.data, prefix.bytelen); req.ifal.ifal_prefixlen = prefix.bitlen; if (req.ifal.ifal_family == AF_UNSPEC) req.ifal.ifal_family = AF_INET6; if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) return -2; return 0; } static int flush_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { struct rtnl_handle rth2; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[IFAL_MAX+1]; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) return -1; parse_rtattr(tb, IFAL_MAX, RTM_RTA(r), len); if (tb[IFAL_ADDRESS]) { n->nlmsg_type = RTM_DELADDRLABEL; n->nlmsg_flags = NLM_F_REQUEST; if (rtnl_open(&rth2, 0) < 0) return -1; if (rtnl_talk(&rth2, n, NULL, 0) < 0) return -2; rtnl_close(&rth2); } return 0; } static int ipaddrlabel_flush(int argc, char **argv) { int af = preferred_family; if (af == AF_UNSPEC) af = AF_INET6; if (argc > 0) { fprintf(stderr, "\"ip addrlabel flush\" does not allow extra arguments\n"); return -1; } if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) { perror("Cannot send dump request"); return -1; } if (rtnl_dump_filter(&rth, flush_addrlabel, NULL) < 0) { fprintf(stderr, "Flush terminated\n"); return -1; } return 0; }
int parse_egress(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { int argc = *argc_p; char **argv = *argv_p; int ok = 0, iok = 0, mirror=0,redir=0; struct tc_mirred p; struct rtattr *tail; char d[16]; memset(d,0,sizeof(d)-1); memset(&p,0,sizeof(struct tc_mirred)); while (argc > 0) { if (matches(*argv, "action") == 0) { break; } else if (matches(*argv, "egress") == 0) { NEXT_ARG(); ok++; continue; } else { if (matches(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&p.index, *argv, 10)) { fprintf(stderr, "Illegal \"index\"\n"); return -1; } iok++; if (!ok) { argc--; argv++; break; } } else if(!ok) { fprintf(stderr, "was expecting egress (%s)\n", *argv); break; } else if (!mirror && matches(*argv, "mirror") == 0) { mirror=1; if (redir) { fprintf(stderr, "Cant have both mirror and redir\n"); return -1; } p.eaction = TCA_EGRESS_MIRROR; p.action = TC_ACT_PIPE; ok++; } else if (!redir && matches(*argv, "redirect") == 0) { redir=1; if (mirror) { fprintf(stderr, "Cant have both mirror and redir\n"); return -1; } p.eaction = TCA_EGRESS_REDIR; p.action = TC_ACT_STOLEN; ok++; } else if ((redir || mirror) && matches(*argv, "dev") == 0) { NEXT_ARG(); if (strlen(d)) duparg("dev", *argv); strncpy(d, *argv, sizeof(d)-1); argc--; argv++; break; } } NEXT_ARG(); } if (!ok && !iok) { return -1; } if (d[0]) { int idx; ll_init_map(&rth); if ((idx = ll_name_to_index(d)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return -1; } p.ifindex = idx; } if (argc && p.eaction == TCA_EGRESS_MIRROR) { if (matches(*argv, "reclassify") == 0) { p.action = TC_POLICE_RECLASSIFY; NEXT_ARG(); } else if (matches(*argv, "pipe") == 0) { p.action = TC_POLICE_PIPE; NEXT_ARG(); } else if (matches(*argv, "drop") == 0 || matches(*argv, "shot") == 0) { p.action = TC_POLICE_SHOT; NEXT_ARG(); } else if (matches(*argv, "continue") == 0) { p.action = TC_POLICE_UNSPEC; NEXT_ARG(); } else if (matches(*argv, "pass") == 0) { p.action = TC_POLICE_OK; NEXT_ARG(); } } if (argc) { if (iok && matches(*argv, "index") == 0) { fprintf(stderr, "mirred: Illegal double index\n"); return -1; } else { if (matches(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&p.index, *argv, 10)) { fprintf(stderr, "mirred: Illegal \"index\"\n"); return -1; } argc--; argv++; } } } tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, tca_id, NULL, 0); addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof (p)); tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; *argc_p = argc; *argv_p = argv; return 0; }
static int vlan_modify(int cmd, int argc, char **argv) { struct { struct nlmsghdr n; struct ifinfomsg ifm; char buf[1024]; } req = { .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), .n.nlmsg_flags = NLM_F_REQUEST, .n.nlmsg_type = cmd, .ifm.ifi_family = PF_BRIDGE, }; char *d = NULL; short vid = -1; short vid_end = -1; struct rtattr *afspec; struct bridge_vlan_info vinfo = {}; unsigned short flags = 0; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); d = *argv; } else if (strcmp(*argv, "vid") == 0) { char *p; NEXT_ARG(); p = strchr(*argv, '-'); if (p) { *p = '\0'; p++; vid = atoi(*argv); vid_end = atoi(p); vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN; } else { vid = atoi(*argv); } } else if (strcmp(*argv, "self") == 0) { flags |= BRIDGE_FLAGS_SELF; } else if (strcmp(*argv, "master") == 0) { flags |= BRIDGE_FLAGS_MASTER; } else if (strcmp(*argv, "pvid") == 0) { vinfo.flags |= BRIDGE_VLAN_INFO_PVID; } else if (strcmp(*argv, "untagged") == 0) { vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED; } else { if (matches(*argv, "help") == 0) { NEXT_ARG(); } } argc--; argv++; } if (d == NULL || vid == -1) { fprintf(stderr, "Device and VLAN ID are required arguments.\n"); return -1; } req.ifm.ifi_index = ll_name_to_index(d); if (req.ifm.ifi_index == 0) { fprintf(stderr, "Cannot find bridge device \"%s\"\n", d); return -1; } if (vid >= 4096) { fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid); return -1; } if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) { if (vid_end == -1 || vid_end >= 4096 || vid >= vid_end) { fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n", vid, vid_end); return -1; } if (vinfo.flags & BRIDGE_VLAN_INFO_PVID) { fprintf(stderr, "pvid cannot be configured for a vlan range\n"); return -1; } } afspec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC); if (flags) addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags); vinfo.vid = vid; if (vid_end != -1) { /* send vlan range start */ addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo, sizeof(vinfo)); vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN; /* Now send the vlan range end */ vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END; vinfo.vid = vid_end; addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo, sizeof(vinfo)); } else { addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo, sizeof(vinfo)); } addattr_nest_end(&req.n, afspec); if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) return -1; return 0; } /* In order to use this function for both filtering and non-filtering cases * we need to make it a tristate: * return -1 - if filtering we've gone over so don't continue * return 0 - skip entry and continue (applies to range start or to entries * which are less than filter_vlan) * return 1 - print the entry and continue */ static int filter_vlan_check(struct bridge_vlan_info *vinfo) { /* if we're filtering we should stop on the first greater entry */ if (filter_vlan && vinfo->vid > filter_vlan && !(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)) return -1; if ((vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) || vinfo->vid < filter_vlan) return 0; return 1; } static void print_vlan_port(FILE *fp, int ifi_index) { if (jw_global) { jsonw_pretty(jw_global, 1); jsonw_name(jw_global, ll_index_to_name(ifi_index)); jsonw_start_array(jw_global); } else { fprintf(fp, "%s", ll_index_to_name(ifi_index)); } } static void start_json_vlan_flags_array(bool *vlan_flags) { if (*vlan_flags) return; jsonw_name(jw_global, "flags"); jsonw_start_array(jw_global); *vlan_flags = true; } static int print_vlan(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = arg; struct ifinfomsg *ifm = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[IFLA_MAX+1]; bool vlan_flags; if (n->nlmsg_type != RTM_NEWLINK) { fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } len -= NLMSG_LENGTH(sizeof(*ifm)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } if (ifm->ifi_family != AF_BRIDGE) return 0; if (filter_index && filter_index != ifm->ifi_index) return 0; parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len); /* if AF_SPEC isn't there, vlan table is not preset for this port */ if (!tb[IFLA_AF_SPEC]) { if (!filter_vlan) fprintf(fp, "%s\tNone\n", ll_index_to_name(ifm->ifi_index)); return 0; } else { struct rtattr *i, *list = tb[IFLA_AF_SPEC]; int rem = RTA_PAYLOAD(list); __u16 last_vid_start = 0; if (!filter_vlan) print_vlan_port(fp, ifm->ifi_index); for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { struct bridge_vlan_info *vinfo; int vcheck_ret; if (i->rta_type != IFLA_BRIDGE_VLAN_INFO) continue; vinfo = RTA_DATA(i); if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)) last_vid_start = vinfo->vid; vcheck_ret = filter_vlan_check(vinfo); if (vcheck_ret == -1) break; else if (vcheck_ret == 0) continue; if (filter_vlan) print_vlan_port(fp, ifm->ifi_index); if (jw_global) { jsonw_start_object(jw_global); jsonw_uint_field(jw_global, "vlan", last_vid_start); if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) continue; } else { fprintf(fp, "\t %hu", last_vid_start); } if (last_vid_start != vinfo->vid) { if (jw_global) jsonw_uint_field(jw_global, "vlanEnd", vinfo->vid); else fprintf(fp, "-%hu", vinfo->vid); } if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) { if (jw_global) { start_json_vlan_flags_array(&vlan_flags); jsonw_string(jw_global, "PVID"); } else { fprintf(fp, " PVID"); } } if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) { if (jw_global) { start_json_vlan_flags_array(&vlan_flags); jsonw_string(jw_global, "Egress Untagged"); } else { fprintf(fp, " Egress Untagged"); } } if (vlan_flags) { jsonw_end_array(jw_global); vlan_flags = false; } if (jw_global) jsonw_end_object(jw_global); else fprintf(fp, "\n"); } } if (!filter_vlan) { if (jw_global) jsonw_end_array(jw_global); else fprintf(fp, "\n"); } fflush(fp); return 0; }
static int ila_parse_opt(int argc, char **argv, struct nlmsghdr *n, bool adding) { __u64 locator = 0; __u64 locator_match = 0; int ifindex = 0; int csum_mode = 0; int ident_type = 0; bool loc_set = false; bool loc_match_set = false; bool ifindex_set = false; bool csum_mode_set = false; bool ident_type_set = false; while (argc > 0) { if (!matches(*argv, "loc")) { NEXT_ARG(); if (get_addr64(&locator, *argv) < 0) { fprintf(stderr, "Bad locator: %s\n", *argv); return -1; } loc_set = true; } else if (!matches(*argv, "loc_match")) { NEXT_ARG(); if (get_addr64(&locator_match, *argv) < 0) { fprintf(stderr, "Bad locator to match: %s\n", *argv); return -1; } loc_match_set = true; } else if (!matches(*argv, "csum-mode")) { NEXT_ARG(); csum_mode = ila_csum_name2mode(*argv); if (csum_mode < 0) { fprintf(stderr, "Bad csum-mode: %s\n", *argv); return -1; } csum_mode_set = true; } else if (!matches(*argv, "ident-type")) { NEXT_ARG(); ident_type = ila_ident_name2type(*argv); if (ident_type < 0) { fprintf(stderr, "Bad ident-type: %s\n", *argv); return -1; } ident_type_set = true; } else if (!matches(*argv, "dev")) { NEXT_ARG(); ifindex = ll_name_to_index(*argv); if (ifindex == 0) { fprintf(stderr, "No such interface: %s\n", *argv); return -1; } ifindex_set = true; } else { usage(); return -1; } argc--, argv++; } if (adding) { if (!loc_set) { fprintf(stderr, "ila: missing locator\n"); return -1; } if (!loc_match_set) { fprintf(stderr, "ila: missing locator0match\n"); return -1; } } if (loc_match_set) addattr64(n, 1024, ILA_ATTR_LOCATOR_MATCH, locator_match); if (loc_set) addattr64(n, 1024, ILA_ATTR_LOCATOR, locator); if (ifindex_set) addattr32(n, 1024, ILA_ATTR_IFINDEX, ifindex); if (csum_mode_set) addattr8(n, 1024, ILA_ATTR_CSUM_MODE, csum_mode); if (ident_type_set) addattr8(n, 1024, ILA_ATTR_IDENT_TYPE, ident_type); return 0; }
REQ iproute_get(int argc, char *argv) { REQ req; char *idev = NULL; char *odev = NULL; int connected = 0; int from_ok = 0; memset(&req, 0, sizeof(req)); iproute_reset_filter(); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETROUTE; req.r.rtm_family = preferred_family; req.r.rtm_table = 0; req.r.rtm_protocol = 0; req.r.rtm_scope = 0; req.r.rtm_type = 0; req.r.rtm_src_len = 0; req.r.rtm_dst_len = 0; req.r.rtm_tos = 0; while (argc > 0) { 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, "from") == 0) { inet_prefix addr; NEXT_ARG(); from_ok = 1; 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(matches(argv, "iif") == 0) { NEXT_ARG(); idev = argv; } else if(matches(argv, "oif") == 0 || strcmp(argv, "dev") == 0) { NEXT_ARG(); odev = argv; } else if(matches(argv, "notify") == 0) { req.r.rtm_flags |= RTM_F_NOTIFY; } else if(matches(argv, "connected") == 0) { connected = 1; } else { inet_prefix addr; if(strcmp(argv, "to") == 0) { 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_DST, &addr.data, addr.bytelen); req.r.rtm_dst_len = addr.bitlen; } argc--; argv++; } if(req.r.rtm_dst_len == 0) { fprintf(stderr, "need at least destination address\n"); exit(1); } ll_init_map(&rth); if(idev || odev) { int idx; if(idev) { if((idx = ll_name_to_index(idev)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", idev); //return -1; exit(1); } addattr32(&req.n, sizeof(req), RTA_IIF, idx); } if(odev) { if((idx = ll_name_to_index(odev)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", odev); //return -1; exit(1); } addattr32(&req.n, sizeof(req), RTA_OIF, idx); } } if(req.r.rtm_family == AF_UNSPEC) req.r.rtm_family = AF_INET; if(rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) exit(2); if(connected && !from_ok) { struct rtmsg *r = NLMSG_DATA(&req.n); int len = req.n.nlmsg_len; struct rtattr * tb[RTA_MAX+1]; // if(print_route(NULL, &req.n, (void*)stdout) < 0) { // fprintf(stderr, "An error :-)\n"); // exit(1); // } if(req.n.nlmsg_type != RTM_NEWROUTE) { fprintf(stderr, "Not a route?\n"); //return -1; exit(1); } len -= NLMSG_LENGTH(sizeof(*r)); if(len < 0) { fprintf(stderr, "Wrong len %d\n", len); //return -1; exit(1); } parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); if(tb[RTA_PREFSRC]) { tb[RTA_PREFSRC]->rta_type = RTA_SRC; r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]); } else if(!tb[RTA_SRC]) { fprintf(stderr, "Failed to connect the route\n"); //return -1; exit(1); } if(!odev && tb[RTA_OIF]) tb[RTA_OIF]->rta_type = 0; if(tb[RTA_GATEWAY]) tb[RTA_GATEWAY]->rta_type = 0; if(!idev && tb[RTA_IIF]) tb[RTA_IIF]->rta_type = 0; req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETROUTE; if(rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) exit(2); } // if(print_route(NULL, &req.n, (void*)stdout) < 0) { // fprintf(stderr, "An error :-)\n"); // exit(1); // } // exit(0); return req; }
static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) { int len; char *dev = NULL; char *name = NULL; char *link = NULL; char *type = NULL; int group; struct link_util *lu = NULL; struct iplink_req req; int ret; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.i.ifi_family = preferred_family; ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev, &group); if (ret < 0) return ret; argc -= ret; argv += ret; if (group != -1) { if (dev) addattr_l(&req.n, sizeof(req), IFLA_GROUP, &group, sizeof(group)); else { if (argc) { fprintf(stderr, "Garbage instead of arguments " "\"%s ...\". Try \"ip link " "help\".\n", *argv); return -1; } if (flags & NLM_F_CREATE) { fprintf(stderr, "group cannot be used when " "creating devices.\n"); return -1; } req.i.ifi_index = 0; addattr32(&req.n, sizeof(req), IFLA_GROUP, group); if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) exit(2); return 0; } } ll_init_map(&rth); if (!(flags & NLM_F_CREATE)) { if (!dev) { fprintf(stderr, "Not enough information: \"dev\" " "argument is required.\n"); exit(-1); } req.i.ifi_index = ll_name_to_index(dev); if (req.i.ifi_index == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", dev); return -1; } } else { /* Allow "ip link add dev" and "ip link add name" */ if (!name) name = dev; if (link) { int ifindex; ifindex = ll_name_to_index(link); if (ifindex == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", link); return -1; } addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4); } } if (name) { len = strlen(name) + 1; if (len == 1) invarg("\"\" is not a valid device identifier\n", "name"); if (len > IFNAMSIZ) invarg("\"name\" too long\n", name); addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len); } if (type) { struct rtattr *linkinfo = NLMSG_TAIL(&req.n); addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type, strlen(type)); lu = get_link_kind(type); if (lu && argc) { struct rtattr * data = NLMSG_TAIL(&req.n); addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); if (lu->parse_opt && lu->parse_opt(lu, argc, argv, &req.n)) return -1; data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; } else if (argc) { if (matches(*argv, "help") == 0) usage(); fprintf(stderr, "Garbage instead of arguments \"%s ...\". " "Try \"ip link help\".\n", *argv); return -1; } linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; } else if (flags & NLM_F_CREATE) { fprintf(stderr, "Not enough information: \"type\" argument " "is required\n"); return -1; } if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) exit(2); return 0; }
oob_intf* oob_intf_create(const char *name, const uint8_t mac[6]) { int rc; int flags; struct ifreq ifr; oob_intf *intf = NULL; #define _CHECK_RC(fmt, ...) do { \ if (rc < 0) { \ rc = errno; \ LOG_ERR(rc, fmt, ##__VA_ARGS__); \ goto err_out; \ } \ } while(0) intf = malloc(sizeof(*intf)); if (!intf) { rc = ENOMEM; LOG_ERR(rc, "Failed to allocate memory for interface"); goto err_out; } memset(intf, 0, sizeof(*intf)); strncpy(intf->oi_name, name, sizeof(intf->oi_name)); intf->oi_name[sizeof(intf->oi_name) - 1] = '\0'; intf->oi_fd = -1; rc = rtnl_open(&intf->oi_rth, 0); _CHECK_RC("Failed to open rth_handler"); rc = open(TUN_DEVICE, O_RDWR); _CHECK_RC("Failed to open %s", TUN_DEVICE); intf->oi_fd = rc; memset(&ifr, 0, sizeof(ifr)); /* * IFF_TAP: TAP interface * IFF_NO_PI: Do not provide pracket information */ ifr.ifr_flags = IFF_TAP|IFF_NO_PI; strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0'; rc = ioctl(intf->oi_fd, TUNSETIFF, (void *) &ifr); _CHECK_RC("Failed to create tap interface %s", ifr.ifr_name); /* make fd non-blocking */ rc = fcntl(intf->oi_fd, F_GETFL); _CHECK_RC("Failed to get flags from fd ", intf->oi_fd); flags = rc | O_NONBLOCK; rc = fcntl(intf->oi_fd, F_SETFL, rc); _CHECK_RC("Failed to set non-blocking flags ", flags, " to fd ", intf->oi_fd); /* set CLOEXEC */ rc = fcntl(intf->oi_fd, F_GETFD); _CHECK_RC("Failed to get flags from fd ", intf->oi_fd); flags = rc | FD_CLOEXEC; rc = fcntl(intf->oi_fd, F_SETFD, flags); _CHECK_RC("Failed to set close-on-exec flags ", flags, " to fd ", intf->oi_fd); // TODO: if needed, we can adjust send buffer size, TUNSETSNDBUF intf->oi_ifidx = ll_name_to_index(intf->oi_name); /* now set the mac address */ oob_intf_set_mac(intf, mac); #if 0 /* make it persistent */ rc = ioctl(intf->oi_fd, TUNSETPERSIST, 0); _CHECK_RC("Failed to make the tap interface %s persistent", intf->oi_name); #endif LOG_INFO("Create/attach to tap interface %s @ fd %d, index %d", intf->oi_name, intf->oi_fd, intf->oi_ifidx); //oob_intf_bring_up(intf); return intf; err_out: if (intf) { rtnl_close(&intf->oi_rth); if (intf->oi_fd != -1) { close(intf->oi_fd); } free(intf); } return NULL; }
static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) { struct qdisc_util *q = NULL; struct tc_estimator est; struct { struct tc_sizespec szopts; __u16 *data; } stab; char d[16]; char k[16]; struct { struct nlmsghdr n; struct tcmsg t; char buf[TCA_BUF_MAX]; } req; memset(&req, 0, sizeof(req)); memset(&stab, 0, sizeof(stab)); memset(&est, 0, sizeof(est)); memset(&d, 0, sizeof(d)); memset(&k, 0, sizeof(k)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.t.tcm_family = AF_UNSPEC; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); if (d[0]) duparg("dev", *argv); strncpy(d, *argv, sizeof(d)-1); } else if (strcmp(*argv, "handle") == 0) { __u32 handle; if (req.t.tcm_handle) duparg("handle", *argv); NEXT_ARG(); if (get_qdisc_handle(&handle, *argv)) invarg("invalid qdisc ID", *argv); req.t.tcm_handle = handle; } else if (strcmp(*argv, "root") == 0) { if (req.t.tcm_parent) { fprintf(stderr, "Error: \"root\" is duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_ROOT; } else if (strcmp(*argv, "clsact") == 0) { if (req.t.tcm_parent) { fprintf(stderr, "Error: \"clsact\" is a duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_CLSACT; strncpy(k, "clsact", sizeof(k) - 1); q = get_qdisc_kind(k); req.t.tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0); NEXT_ARG_FWD(); break; } else if (strcmp(*argv, "ingress") == 0) { if (req.t.tcm_parent) { fprintf(stderr, "Error: \"ingress\" is a duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_INGRESS; strncpy(k, "ingress", sizeof(k) - 1); q = get_qdisc_kind(k); req.t.tcm_handle = TC_H_MAKE(TC_H_INGRESS, 0); NEXT_ARG_FWD(); break; } else if (strcmp(*argv, "parent") == 0) { __u32 handle; NEXT_ARG(); if (req.t.tcm_parent) duparg("parent", *argv); if (get_tc_classid(&handle, *argv)) invarg("invalid parent ID", *argv); req.t.tcm_parent = handle; } else if (matches(*argv, "estimator") == 0) { if (parse_estimator(&argc, &argv, &est)) return -1; } else if (matches(*argv, "stab") == 0) { if (parse_size_table(&argc, &argv, &stab.szopts) < 0) return -1; continue; } else if (matches(*argv, "help") == 0) { usage(); } else { strncpy(k, *argv, sizeof(k)-1); q = get_qdisc_kind(k); argc--; argv++; break; } argc--; argv++; } if (k[0]) addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1); if (est.ewma_log) addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est)); if (q) { if (q->parse_qopt) { if (q->parse_qopt(q, argc, argv, &req.n)) return 1; } else if (argc) { fprintf(stderr, "qdisc '%s' does not support option parsing\n", k); return -1; } } else { if (argc) { if (matches(*argv, "help") == 0) usage(); fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"tc qdisc help\".\n", *argv); return -1; } } if (check_size_table_opts(&stab.szopts)) { struct rtattr *tail; if (tc_calc_size_table(&stab.szopts, &stab.data) < 0) { fprintf(stderr, "failed to calculate size table.\n"); return -1; } tail = NLMSG_TAIL(&req.n); addattr_l(&req.n, sizeof(req), TCA_STAB, NULL, 0); addattr_l(&req.n, sizeof(req), TCA_STAB_BASE, &stab.szopts, sizeof(stab.szopts)); if (stab.data) addattr_l(&req.n, sizeof(req), TCA_STAB_DATA, stab.data, stab.szopts.tsize * sizeof(__u16)); tail->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail; if (stab.data) free(stab.data); } if (d[0]) { int idx; ll_init_map(&rth); if ((idx = ll_name_to_index(d)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return 1; } req.t.tcm_ifindex = idx; } if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) return 2; return 0; }
static int vlan_modify(int cmd, int argc, char **argv) { struct { struct nlmsghdr n; struct ifinfomsg ifm; char buf[1024]; } req; char *d = NULL; short vid = -1; struct rtattr *afspec; struct bridge_vlan_info vinfo; unsigned short flags = 0; memset(&vinfo, 0, sizeof(vinfo)); memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = cmd; req.ifm.ifi_family = PF_BRIDGE; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); d = *argv; } else if (strcmp(*argv, "vid") == 0) { NEXT_ARG(); vid = atoi(*argv); } else if (strcmp(*argv, "self") == 0) { flags |= BRIDGE_FLAGS_SELF; } else if (strcmp(*argv, "master") == 0) { flags |= BRIDGE_FLAGS_MASTER; } else if (strcmp(*argv, "pvid") == 0) { vinfo.flags |= BRIDGE_VLAN_INFO_PVID; } else if (strcmp(*argv, "untagged") == 0) { vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED; } else { if (matches(*argv, "help") == 0) { NEXT_ARG(); } } argc--; argv++; } if (d == NULL || vid == -1) { fprintf(stderr, "Device and VLAN ID are required arguments.\n"); exit(-1); } req.ifm.ifi_index = ll_name_to_index(d); if (req.ifm.ifi_index == 0) { fprintf(stderr, "Cannot find bridge device \"%s\"\n", d); return -1; } if (vid >= 4096) { fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid); return -1; } vinfo.vid = vid; afspec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC); if (flags) addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags); addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo, sizeof(vinfo)); addattr_nest_end(&req.n, afspec); if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) exit(2); return 0; }
int ipaddr_list_or_flush(int argc, char **argv, int flush) { struct nlmsg_list *linfo = NULL; struct nlmsg_list *ainfo = NULL; struct nlmsg_list *l; struct rtnl_handle rth; char *filter_dev = NULL; int no_link = 0; ipaddr_reset_filter(oneline); filter.showqueue = 1; if (filter.family == AF_UNSPEC) filter.family = preferred_family; if (flush) { if (argc <= 0) { fprintf(stderr, "Flush requires arguments.\n"); return -1; } if (filter.family == AF_PACKET) { fprintf(stderr, "Cannot flush link addresses.\n"); return -1; } } while (argc > 0) { if (strcmp(*argv, "to") == 0) { NEXT_ARG(); get_prefix(&filter.pfx, *argv, filter.family); if (filter.family == AF_UNSPEC) filter.family = filter.pfx.family; } else if (strcmp(*argv, "scope") == 0) { int scope = 0; NEXT_ARG(); filter.scopemask = -1; if (rtnl_rtscope_a2n(&scope, *argv)) { if (strcmp(*argv, "all") != 0) invarg("invalid \"scope\"\n", *argv); scope = RT_SCOPE_NOWHERE; filter.scopemask = 0; } filter.scope = scope; } else if (strcmp(*argv, "up") == 0) { filter.up = 1; } else if (strcmp(*argv, "dynamic") == 0) { filter.flags &= ~IFA_F_PERMANENT; filter.flagmask |= IFA_F_PERMANENT; } else if (strcmp(*argv, "permanent") == 0) { filter.flags |= IFA_F_PERMANENT; filter.flagmask |= IFA_F_PERMANENT; } else if (strcmp(*argv, "secondary") == 0) { filter.flags |= IFA_F_SECONDARY; filter.flagmask |= IFA_F_SECONDARY; } else if (strcmp(*argv, "primary") == 0) { filter.flags &= ~IFA_F_SECONDARY; filter.flagmask |= IFA_F_SECONDARY; } else if (strcmp(*argv, "tentative") == 0) { filter.flags |= IFA_F_TENTATIVE; filter.flagmask |= IFA_F_TENTATIVE; } else if (strcmp(*argv, "deprecated") == 0) { filter.flags |= IFA_F_DEPRECATED; filter.flagmask |= IFA_F_DEPRECATED; } else if (strcmp(*argv, "label") == 0) { NEXT_ARG(); filter.label = *argv; } else { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); } if (matches(*argv, "help") == 0) usage(); if (filter_dev) duparg2("dev", *argv); filter_dev = *argv; } argv++; argc--; } if (rtnl_open(&rth, 0) < 0) exit(1); if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(&rth, store_nlmsg, &linfo, NULL, NULL) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } if (filter_dev) { filter.ifindex = ll_name_to_index(filter_dev); if (filter.ifindex <= 0) { fprintf(stderr, "Device \"%s\" does not exist.\n", filter_dev); return -1; } } if (flush) { int round = 0; char flushb[4096-512]; filter.flushb = flushb; filter.flushp = 0; filter.flushe = sizeof(flushb); filter.rth = &rth; for (;;) { if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) { perror("Cannot send dump request"); exit(1); } filter.flushed = 0; if (rtnl_dump_filter(&rth, print_addrinfo, stdout, NULL, NULL) < 0) { fprintf(stderr, "Flush terminated\n"); exit(1); } if (filter.flushed == 0) { if (round == 0) { fprintf(stderr, "Nothing to flush.\n"); } else if (show_stats) printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":""); fflush(stdout); return 0; } round++; if (flush_update() < 0) exit(1); if (show_stats) { printf("\n*** Round %d, deleting %d addresses ***\n", round, filter.flushed); fflush(stdout); } } } if (filter.family != AF_PACKET) { if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(&rth, store_nlmsg, &ainfo, NULL, NULL) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } } if (filter.family && filter.family != AF_PACKET) { struct nlmsg_list **lp; lp=&linfo; if (filter.oneline) no_link = 1; while ((l=*lp)!=NULL) { int ok = 0; struct ifinfomsg *ifi = NLMSG_DATA(&l->h); struct nlmsg_list *a; for (a=ainfo; a; a=a->next) { struct nlmsghdr *n = &a->h; struct ifaddrmsg *ifa = NLMSG_DATA(n); if (ifa->ifa_index != ifi->ifi_index || (filter.family && filter.family != ifa->ifa_family)) continue; if ((filter.scope^ifa->ifa_scope)&filter.scopemask) continue; if ((filter.flags^ifa->ifa_flags)&filter.flagmask) continue; if (filter.pfx.family || filter.label) { struct rtattr *tb[IFA_MAX+1]; parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n)); if (!tb[IFA_LOCAL]) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (filter.pfx.family && tb[IFA_LOCAL]) { inet_prefix dst; memset(&dst, 0, sizeof(dst)); dst.family = ifa->ifa_family; memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) continue; } if (filter.label) { SPRINT_BUF(b1); const char *label; if (tb[IFA_LABEL]) label = RTA_DATA(tb[IFA_LABEL]); else label = ll_idx_n2a(ifa->ifa_index, b1); if (fnmatch(filter.label, label, 0) != 0) continue; } } ok = 1; break; } if (!ok) *lp = l->next; else lp = &l->next; } } for (l=linfo; l; l = l->next) { if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) { struct ifinfomsg *ifi = NLMSG_DATA(&l->h); if (filter.family != AF_PACKET) print_selected_addrinfo(ifi->ifi_index, ainfo, stdout); } fflush(stdout); } exit(0); }
static int brlink_modify(int argc, char **argv) { struct { struct nlmsghdr n; struct ifinfomsg ifm; char buf[512]; } req; char *d = NULL; __s8 learning = -1; __s8 learning_sync = -1; __s8 flood = -1; __s8 hairpin = -1; __s8 bpdu_guard = -1; __s8 fast_leave = -1; __s8 root_block = -1; __u32 cost = 0; __s16 priority = -1; __s8 state = -1; __s16 mode = -1; __u16 flags = 0; struct rtattr *nest; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_SETLINK; req.ifm.ifi_family = PF_BRIDGE; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); d = *argv; } else if (strcmp(*argv, "guard") == 0) { NEXT_ARG(); if (!on_off("guard", &bpdu_guard, *argv)) exit(-1); } else if (strcmp(*argv, "hairpin") == 0) { NEXT_ARG(); if (!on_off("hairping", &hairpin, *argv)) exit(-1); } else if (strcmp(*argv, "fastleave") == 0) { NEXT_ARG(); if (!on_off("fastleave", &fast_leave, *argv)) exit(-1); } else if (strcmp(*argv, "root_block") == 0) { NEXT_ARG(); if (!on_off("root_block", &root_block, *argv)) exit(-1); } else if (strcmp(*argv, "learning") == 0) { NEXT_ARG(); if (!on_off("learning", &learning, *argv)) exit(-1); } else if (strcmp(*argv, "learning_sync") == 0) { NEXT_ARG(); if (!on_off("learning_sync", &learning_sync, *argv)) exit(-1); } else if (strcmp(*argv, "flood") == 0) { NEXT_ARG(); if (!on_off("flood", &flood, *argv)) exit(-1); } else if (strcmp(*argv, "cost") == 0) { NEXT_ARG(); cost = atoi(*argv); } else if (strcmp(*argv, "priority") == 0) { NEXT_ARG(); priority = atoi(*argv); } else if (strcmp(*argv, "state") == 0) { NEXT_ARG(); char *endptr; size_t nstates = sizeof(port_states) / sizeof(*port_states); state = strtol(*argv, &endptr, 10); if (!(**argv != '\0' && *endptr == '\0')) { for (state = 0; state < nstates; state++) if (strcmp(port_states[state], *argv) == 0) break; if (state == nstates) { fprintf(stderr, "Error: invalid STP port state\n"); exit(-1); } } } else if (strcmp(*argv, "hwmode") == 0) { NEXT_ARG(); flags = BRIDGE_FLAGS_SELF; if (strcmp(*argv, "vepa") == 0) mode = BRIDGE_MODE_VEPA; else if (strcmp(*argv, "veb") == 0) mode = BRIDGE_MODE_VEB; else { fprintf(stderr, "Mode argument must be \"vepa\" or " "\"veb\".\n"); exit(-1); } } else if (strcmp(*argv, "self") == 0) { flags = BRIDGE_FLAGS_SELF; } else { usage(); } argc--; argv++; } if (d == NULL) { fprintf(stderr, "Device is a required argument.\n"); exit(-1); } req.ifm.ifi_index = ll_name_to_index(d); if (req.ifm.ifi_index == 0) { fprintf(stderr, "Cannot find bridge device \"%s\"\n", d); exit(-1); } /* Nested PROTINFO attribute. Contains: port flags, cost, priority and * state. */ nest = addattr_nest(&req.n, sizeof(req), IFLA_PROTINFO | NLA_F_NESTED); /* Flags first */ if (bpdu_guard >= 0) addattr8(&req.n, sizeof(req), IFLA_BRPORT_GUARD, bpdu_guard); if (hairpin >= 0) addattr8(&req.n, sizeof(req), IFLA_BRPORT_MODE, hairpin); if (fast_leave >= 0) addattr8(&req.n, sizeof(req), IFLA_BRPORT_FAST_LEAVE, fast_leave); if (root_block >= 0) addattr8(&req.n, sizeof(req), IFLA_BRPORT_PROTECT, root_block); if (flood >= 0) addattr8(&req.n, sizeof(req), IFLA_BRPORT_UNICAST_FLOOD, flood); if (learning >= 0) addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING, learning); if (learning_sync >= 0) addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING_SYNC, learning_sync); if (cost > 0) addattr32(&req.n, sizeof(req), IFLA_BRPORT_COST, cost); if (priority >= 0) addattr16(&req.n, sizeof(req), IFLA_BRPORT_PRIORITY, priority); if (state >= 0) addattr8(&req.n, sizeof(req), IFLA_BRPORT_STATE, state); addattr_nest_end(&req.n, nest); /* IFLA_AF_SPEC nested attribute. Contains IFLA_BRIDGE_FLAGS that * designates master or self operation and IFLA_BRIDGE_MODE * for hw 'vepa' or 'veb' operation modes. The hwmodes are * only valid in 'self' mode on some devices so far. */ if (mode >= 0 || flags > 0) { nest = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC); if (flags > 0) addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags); if (mode >= 0) addattr16(&req.n, sizeof(req), IFLA_BRIDGE_MODE, mode); addattr_nest_end(&req.n, nest); } if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) exit(2); return 0; }
int ipaddr_list_or_flush(int argc, char **argv, int flush) { static const char *const option[] = { "to", "scope", "up", "label", "dev", 0 }; struct nlmsg_list *linfo = NULL; struct nlmsg_list *ainfo = NULL; struct nlmsg_list *l; struct rtnl_handle rth; char *filter_dev = NULL; int no_link = 0; ipaddr_reset_filter(oneline); filter.showqueue = 1; if (filter.family == AF_UNSPEC) filter.family = preferred_family; if (flush) { if (argc <= 0) { bb_error_msg(bb_msg_requires_arg, "flush"); return -1; } if (filter.family == AF_PACKET) { bb_error_msg("cannot flush link addresses"); return -1; } } while (argc > 0) { const int option_num = index_in_str_array(option, *argv); switch (option_num) { case 0: /* to */ NEXT_ARG(); get_prefix(&filter.pfx, *argv, filter.family); if (filter.family == AF_UNSPEC) { filter.family = filter.pfx.family; } break; case 1: /* scope */ { uint32_t scope = 0; NEXT_ARG(); filter.scopemask = -1; if (rtnl_rtscope_a2n(&scope, *argv)) { if (strcmp(*argv, "all") != 0) { invarg(*argv, "scope"); } scope = RT_SCOPE_NOWHERE; filter.scopemask = 0; } filter.scope = scope; break; } case 2: /* up */ filter.up = 1; break; case 3: /* label */ NEXT_ARG(); filter.label = *argv; break; case 4: /* dev */ NEXT_ARG(); default: if (filter_dev) { duparg2("dev", *argv); } filter_dev = *argv; } argv++; argc--; } if (rtnl_open(&rth, 0) < 0) exit(1); if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) { bb_perror_msg_and_die("cannot send dump request"); } if (rtnl_dump_filter(&rth, store_nlmsg, &linfo, NULL, NULL) < 0) { bb_error_msg_and_die("dump terminated"); } if (filter_dev) { filter.ifindex = ll_name_to_index(filter_dev); if (filter.ifindex <= 0) { bb_error_msg("device \"%s\" does not exist", filter_dev); return -1; } } if (flush) { char flushb[4096-512]; filter.flushb = flushb; filter.flushp = 0; filter.flushe = sizeof(flushb); filter.rth = &rth; for (;;) { if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) { perror("Cannot send dump request"); exit(1); } filter.flushed = 0; if (rtnl_dump_filter(&rth, print_addrinfo, stdout, NULL, NULL) < 0) { fprintf(stderr, "Flush terminated\n"); exit(1); } if (filter.flushed == 0) { fflush(stdout); return 0; } if (flush_update() < 0) exit(1); } } if (filter.family != AF_PACKET) { if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) { bb_perror_msg_and_die("cannot send dump request"); } if (rtnl_dump_filter(&rth, store_nlmsg, &ainfo, NULL, NULL) < 0) { bb_error_msg_and_die("dump terminated"); } } if (filter.family && filter.family != AF_PACKET) { struct nlmsg_list **lp; lp=&linfo; if (filter.oneline) no_link = 1; while ((l=*lp)!=NULL) { int ok = 0; struct ifinfomsg *ifi = NLMSG_DATA(&l->h); struct nlmsg_list *a; for (a=ainfo; a; a=a->next) { struct nlmsghdr *n = &a->h; struct ifaddrmsg *ifa = NLMSG_DATA(n); if (ifa->ifa_index != ifi->ifi_index || (filter.family && filter.family != ifa->ifa_family)) continue; if ((filter.scope^ifa->ifa_scope)&filter.scopemask) continue; if ((filter.flags^ifa->ifa_flags)&filter.flagmask) continue; if (filter.pfx.family || filter.label) { struct rtattr *tb[IFA_MAX+1]; memset(tb, 0, sizeof(tb)); parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n)); if (!tb[IFA_LOCAL]) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (filter.pfx.family && tb[IFA_LOCAL]) { inet_prefix dst; memset(&dst, 0, sizeof(dst)); dst.family = ifa->ifa_family; memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) continue; } if (filter.label) { SPRINT_BUF(b1); const char *label; if (tb[IFA_LABEL]) label = RTA_DATA(tb[IFA_LABEL]); else label = ll_idx_n2a(ifa->ifa_index, b1); if (fnmatch(filter.label, label, 0) != 0) continue; } } ok = 1; break; } if (!ok) *lp = l->next; else lp = &l->next; } } for (l=linfo; l; l = l->next) { if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) { struct ifinfomsg *ifi = NLMSG_DATA(&l->h); if (filter.family != AF_PACKET) print_selected_addrinfo(ifi->ifi_index, ainfo, stdout); } fflush(stdout); } exit(0); }
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 tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) { struct qdisc_util *q = NULL; struct tc_estimator est; char d[16]; char k[16]; struct { struct nlmsghdr n; struct tcmsg t; char buf[TCA_BUF_MAX]; } req; memset(&req, 0, sizeof(req)); memset(&est, 0, sizeof(est)); memset(&d, 0, sizeof(d)); memset(&k, 0, sizeof(k)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.t.tcm_family = AF_UNSPEC; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); if (d[0]) duparg("dev", *argv); strncpy(d, *argv, sizeof(d)-1); } else if (strcmp(*argv, "handle") == 0) { __u32 handle; if (req.t.tcm_handle) duparg("handle", *argv); NEXT_ARG(); if (get_qdisc_handle(&handle, *argv)) invarg(*argv, "invalid qdisc ID"); req.t.tcm_handle = handle; } else if (strcmp(*argv, "root") == 0) { if (req.t.tcm_parent) { fprintf(stderr, "Error: \"root\" is duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_ROOT; #ifdef TC_H_INGRESS } else if (strcmp(*argv, "ingress") == 0) { if (req.t.tcm_parent) { fprintf(stderr, "Error: \"ingress\" is a duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_INGRESS; strncpy(k, "ingress", sizeof(k)-1); q = get_qdisc_kind(k); req.t.tcm_handle = 0xffff0000; argc--; argv++; break; #endif } else if (strcmp(*argv, "parent") == 0) { __u32 handle; NEXT_ARG(); if (req.t.tcm_parent) duparg("parent", *argv); if (get_tc_classid(&handle, *argv)) invarg(*argv, "invalid parent ID"); req.t.tcm_parent = handle; } else if (matches(*argv, "estimator") == 0) { if (parse_estimator(&argc, &argv, &est)) return -1; } else if (matches(*argv, "help") == 0) { usage(); } else { strncpy(k, *argv, sizeof(k)-1); q = get_qdisc_kind(k); argc--; argv++; break; } argc--; argv++; } if (k[0]) addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1); if (est.ewma_log) addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est)); if (q) { if (!q->parse_qopt) { fprintf(stderr, "qdisc '%s' does not support option parsing\n", k); return -1; } if (q->parse_qopt(q, argc, argv, &req.n)) return 1; } else { if (argc) { if (matches(*argv, "help") == 0) usage(); fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"tc qdisc help\".\n", *argv); return -1; } } if (d[0]) { int idx; ll_init_map(&rth); if ((idx = ll_name_to_index(d)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return 1; } req.t.tcm_ifindex = idx; } if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) return 2; return 0; }
static int iproute_list_or_flush(int argc, char **argv, int flush) { int do_ipv6 = preferred_family; struct rtnl_handle rth; char *id = NULL; char *od = NULL; iproute_reset_filter(); filter.tb = RT_TABLE_MAIN; if (flush && argc <= 0) { fprintf(stderr, "\"ip route flush\" requires arguments.\n"); return -1; } while (argc > 0) { if (matches(*argv, "protocol") == 0) { int prot = 0; NEXT_ARG(); filter.protocolmask = -1; if (rtnl_rtprot_a2n(&prot, *argv)) { if (strcmp(*argv, "all") != 0) { invarg("invalid \"protocol\"\n", *argv); } prot = 0; filter.protocolmask = 0; } filter.protocol = prot; } else if (strcmp(*argv, "dev") == 0 || strcmp(*argv, "oif") == 0) { NEXT_ARG(); od = *argv; } else if (strcmp(*argv, "iif") == 0) { NEXT_ARG(); id = *argv; } else if (matches(*argv, "from") == 0) { NEXT_ARG(); if (matches(*argv, "root") == 0) { NEXT_ARG(); get_prefix(&filter.rsrc, *argv, do_ipv6); } else if (matches(*argv, "match") == 0) { NEXT_ARG(); get_prefix(&filter.msrc, *argv, do_ipv6); } else { if (matches(*argv, "exact") == 0) { NEXT_ARG(); } get_prefix(&filter.msrc, *argv, do_ipv6); filter.rsrc = filter.msrc; } } else { if (matches(*argv, "to") == 0) { NEXT_ARG(); } if (matches(*argv, "root") == 0) { NEXT_ARG(); get_prefix(&filter.rdst, *argv, do_ipv6); } else if (matches(*argv, "match") == 0) { NEXT_ARG(); get_prefix(&filter.mdst, *argv, do_ipv6); } else { if (matches(*argv, "exact") == 0) { NEXT_ARG(); } get_prefix(&filter.mdst, *argv, do_ipv6); filter.rdst = filter.mdst; } } argc--; argv++; } if (do_ipv6 == AF_UNSPEC && filter.tb) { do_ipv6 = AF_INET; } if (rtnl_open(&rth, 0) < 0) { exit(1); } ll_init_map(&rth); if (id || od) { int idx; if (id) { if ((idx = ll_name_to_index(id)) == 0) { bb_error_msg("Cannot find device \"%s\"", id); return -1; } filter.iif = idx; filter.iifmask = -1; } if (od) { if ((idx = ll_name_to_index(od)) == 0) { bb_error_msg("Cannot find device \"%s\"", od); } filter.oif = idx; filter.oifmask = -1; } } if (flush) { int round = 0; char flushb[4096-512]; if (filter.tb == -1) { if (do_ipv6 != AF_INET6) iproute_flush_cache(); if (do_ipv6 == AF_INET) return 0; } filter.flushb = flushb; filter.flushp = 0; filter.flushe = sizeof(flushb); filter.rth = &rth; for (;;) { if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) { perror("Cannot send dump request"); return -1; } filter.flushed = 0; if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) { bb_error_msg("Flush terminated\n"); return -1; } if (filter.flushed == 0) { if (round == 0) { if (filter.tb != -1 || do_ipv6 == AF_INET6) fprintf(stderr, "Nothing to flush.\n"); } fflush(stdout); return 0; } round++; if (flush_update() < 0) exit(1); } } if (filter.tb != -1) { if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) { bb_perror_msg_and_die("Cannot send dump request"); } } else { if (rtnl_rtcache_request(&rth, do_ipv6) < 0) { bb_perror_msg_and_die("Cannot send dump request"); } } if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) { bb_error_msg_and_die("Dump terminated"); } exit(0); }
int do_ipmonitor(int argc, char **argv) { char *file = NULL; unsigned groups = 0; int llink=0; int laddr=0; int lroute=0; int lmroute=0; int lprefix=0; int lneigh=0; int lnetconf=0; int lrule=0; int ifindex=0; groups |= nl_mgrp(RTNLGRP_LINK); groups |= nl_mgrp(RTNLGRP_IPV4_IFADDR); groups |= nl_mgrp(RTNLGRP_IPV6_IFADDR); groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE); groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE); groups |= nl_mgrp(RTNLGRP_IPV4_MROUTE); groups |= nl_mgrp(RTNLGRP_IPV6_MROUTE); groups |= nl_mgrp(RTNLGRP_IPV6_PREFIX); groups |= nl_mgrp(RTNLGRP_NEIGH); groups |= nl_mgrp(RTNLGRP_IPV4_NETCONF); groups |= nl_mgrp(RTNLGRP_IPV6_NETCONF); groups |= nl_mgrp(RTNLGRP_IPV4_RULE); groups |= nl_mgrp(RTNLGRP_IPV6_RULE); rtnl_close(&rth); while (argc > 0) { if (matches(*argv, "file") == 0) { NEXT_ARG(); file = *argv; } else if (matches(*argv, "label") == 0) { prefix_banner = 1; } else if (matches(*argv, "link") == 0) { llink=1; groups = 0; } else if (matches(*argv, "address") == 0) { laddr=1; groups = 0; } else if (matches(*argv, "route") == 0) { lroute=1; groups = 0; } else if (matches(*argv, "mroute") == 0) { lmroute=1; groups = 0; } else if (matches(*argv, "prefix") == 0) { lprefix=1; groups = 0; } else if (matches(*argv, "neigh") == 0) { lneigh = 1; groups = 0; } else if (matches(*argv, "netconf") == 0) { lnetconf = 1; groups = 0; } else if (matches(*argv, "rule") == 0) { lrule = 1; groups = 0; } else if (strcmp(*argv, "all") == 0) { prefix_banner=1; } else if (matches(*argv, "help") == 0) { usage(); } else if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); ifindex = ll_name_to_index(*argv); if (!ifindex) invarg("Device does not exist\n", *argv); } else { fprintf(stderr, "Argument \"%s\" is unknown, try \"ip monitor help\".\n", *argv); exit(-1); } argc--; argv++; } ipaddr_reset_filter(1, ifindex); iproute_reset_filter(ifindex); ipmroute_reset_filter(ifindex); ipneigh_reset_filter(ifindex); ipnetconf_reset_filter(ifindex); if (llink) groups |= nl_mgrp(RTNLGRP_LINK); if (laddr) { if (!preferred_family || preferred_family == AF_INET) groups |= nl_mgrp(RTNLGRP_IPV4_IFADDR); if (!preferred_family || preferred_family == AF_INET6) groups |= nl_mgrp(RTNLGRP_IPV6_IFADDR); } if (lroute) { if (!preferred_family || preferred_family == AF_INET) groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE); if (!preferred_family || preferred_family == AF_INET6) groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE); } if (lmroute) { if (!preferred_family || preferred_family == AF_INET) groups |= nl_mgrp(RTNLGRP_IPV4_MROUTE); if (!preferred_family || preferred_family == AF_INET6) groups |= nl_mgrp(RTNLGRP_IPV6_MROUTE); } if (lprefix) { if (!preferred_family || preferred_family == AF_INET6) groups |= nl_mgrp(RTNLGRP_IPV6_PREFIX); } if (lneigh) { groups |= nl_mgrp(RTNLGRP_NEIGH); } if (lnetconf) { if (!preferred_family || preferred_family == AF_INET) groups |= nl_mgrp(RTNLGRP_IPV4_NETCONF); if (!preferred_family || preferred_family == AF_INET6) groups |= nl_mgrp(RTNLGRP_IPV6_NETCONF); } if (lrule) { if (!preferred_family || preferred_family == AF_INET) groups |= nl_mgrp(RTNLGRP_IPV4_RULE); if (!preferred_family || preferred_family == AF_INET6) groups |= nl_mgrp(RTNLGRP_IPV6_RULE); } if (file) { FILE *fp; fp = fopen(file, "r"); if (fp == NULL) { perror("Cannot fopen"); exit(-1); } return rtnl_from_file(fp, accept_msg, stdout); } if (rtnl_open(&rth, groups) < 0) exit(1); ll_init_map(&rth); if (rtnl_listen(&rth, accept_msg, stdout) < 0) exit(2); return 0; }
static int iproute_get(int argc, char **argv) { struct rtnl_handle rth; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; char *idev = NULL; char *odev = NULL; int connected = 0; int from_ok = 0; const char *options[] = { "from", "iif", "oif", "dev", "notify", "connected", "to", 0 }; memset(&req, 0, sizeof(req)); iproute_reset_filter(); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETROUTE; req.r.rtm_family = preferred_family; req.r.rtm_table = 0; req.r.rtm_protocol = 0; req.r.rtm_scope = 0; req.r.rtm_type = 0; req.r.rtm_src_len = 0; req.r.rtm_dst_len = 0; req.r.rtm_tos = 0; while (argc > 0) { switch (compare_string_array(options, *argv)) { case 0: /* from */ { inet_prefix addr; NEXT_ARG(); from_ok = 1; 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; break; } case 1: /* iif */ NEXT_ARG(); idev = *argv; break; case 2: /* oif */ case 3: /* dev */ NEXT_ARG(); odev = *argv; break; case 4: /* notify */ req.r.rtm_flags |= RTM_F_NOTIFY; break; case 5: /* connected */ connected = 1; break; case 6: /* to */ NEXT_ARG(); default: { inet_prefix addr; 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_DST, &addr.data, addr.bytelen); } req.r.rtm_dst_len = addr.bitlen; } argc--; argv++; } } if (req.r.rtm_dst_len == 0) { bb_error_msg_and_die("need at least destination address"); } if (rtnl_open(&rth, 0) < 0) exit(1); ll_init_map(&rth); if (idev || odev) { int idx; if (idev) { if ((idx = ll_name_to_index(idev)) == 0) { bb_error_msg("Cannot find device \"%s\"", idev); return -1; } addattr32(&req.n, sizeof(req), RTA_IIF, idx); } if (odev) { if ((idx = ll_name_to_index(odev)) == 0) { bb_error_msg("Cannot find device \"%s\"", odev); return -1; } addattr32(&req.n, sizeof(req), RTA_OIF, idx); } } if (req.r.rtm_family == AF_UNSPEC) { req.r.rtm_family = AF_INET; } if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) { exit(2); } if (connected && !from_ok) { struct rtmsg *r = NLMSG_DATA(&req.n); int len = req.n.nlmsg_len; struct rtattr * tb[RTA_MAX+1]; if (print_route(NULL, &req.n, (void*)stdout) < 0) { bb_error_msg_and_die("An error :-)"); } if (req.n.nlmsg_type != RTM_NEWROUTE) { bb_error_msg("Not a route?"); return -1; } len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) { bb_error_msg("Wrong len %d", len); return -1; } memset(tb, 0, sizeof(tb)); parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); if (tb[RTA_PREFSRC]) { tb[RTA_PREFSRC]->rta_type = RTA_SRC; r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]); } else if (!tb[RTA_SRC]) { bb_error_msg("Failed to connect the route"); return -1; } if (!odev && tb[RTA_OIF]) { tb[RTA_OIF]->rta_type = 0; } if (tb[RTA_GATEWAY]) { tb[RTA_GATEWAY]->rta_type = 0; } if (!idev && tb[RTA_IIF]) { tb[RTA_IIF]->rta_type = 0; } req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETROUTE; if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) { exit(2); } } if (print_route(NULL, &req.n, (void*)stdout) < 0) { bb_error_msg_and_die("An error :-)"); } exit(0); }
static int do_tunnels_list(struct ip_tunnel_parm *p) { char name[IFNAMSIZ]; unsigned long rx_bytes, rx_packets, rx_errs, rx_drops, rx_fifo, rx_frame, tx_bytes, tx_packets, tx_errs, tx_drops, tx_fifo, tx_colls, tx_carrier, rx_multi; struct ip_tunnel_parm p1; char buf[512]; FILE *fp = fopen("/proc/net/dev", "r"); if (fp == NULL) { perror("fopen"); return -1; } /* skip header lines */ if (!fgets(buf, sizeof(buf), fp) || !fgets(buf, sizeof(buf), fp)) { fprintf(stderr, "/proc/net/dev read error\n"); fclose(fp); return -1; } while (fgets(buf, sizeof(buf), fp) != NULL) { int index, type; char *ptr; buf[sizeof(buf) - 1] = 0; if ((ptr = strchr(buf, ':')) == NULL || (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) { fprintf(stderr, "Wrong format of /proc/net/dev. Sorry.\n"); fclose(fp); return -1; } if (sscanf(ptr, "%ld%ld%ld%ld%ld%ld%ld%*d%ld%ld%ld%ld%ld%ld%ld", &rx_bytes, &rx_packets, &rx_errs, &rx_drops, &rx_fifo, &rx_frame, &rx_multi, &tx_bytes, &tx_packets, &tx_errs, &tx_drops, &tx_fifo, &tx_colls, &tx_carrier) != 14) continue; if (p->name[0] && strcmp(p->name, name)) continue; index = ll_name_to_index(name); if (index == 0) continue; type = ll_index_to_type(index); if (type == -1) { fprintf(stderr, "Failed to get type of [%s]\n", name); continue; } if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT) continue; memset(&p1, 0, sizeof(p1)); if (tnl_get_ioctl(name, &p1)) continue; if ((p->link && p1.link != p->link) || (p->name[0] && strcmp(p1.name, p->name)) || (p->iph.daddr && p1.iph.daddr != p->iph.daddr) || (p->iph.saddr && p1.iph.saddr != p->iph.saddr) || (p->i_key && p1.i_key != p->i_key)) continue; print_tunnel(&p1); if (show_stats) { printf("%s", _SL_); printf("RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts%s", _SL_); printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-8ld%s", rx_packets, rx_bytes, rx_errs, rx_frame, rx_fifo, rx_multi, _SL_); printf("TX: Packets Bytes Errors DeadLoop NoRoute NoBufs%s", _SL_); printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-6ld", tx_packets, tx_bytes, tx_errs, tx_colls, tx_carrier, tx_drops); } printf("\n"); } fclose(fp); return 0; }
int iplink_parse(int argc, char **argv, struct iplink_req *req, char **name, char **type, char **link, char **dev, int *group) { int ret, len; char abuf[32]; int qlen = -1; int mtu = -1; int netns = -1; int vf = -1; *group = -1; ret = argc; while (argc > 0) { if (strcmp(*argv, "up") == 0) { req->i.ifi_change |= IFF_UP; req->i.ifi_flags |= IFF_UP; } else if (strcmp(*argv, "down") == 0) { req->i.ifi_change |= IFF_UP; req->i.ifi_flags &= ~IFF_UP; } else if (strcmp(*argv, "name") == 0) { NEXT_ARG(); *name = *argv; } else if (matches(*argv, "link") == 0) { NEXT_ARG(); *link = *argv; } else if (matches(*argv, "address") == 0) { NEXT_ARG(); len = ll_addr_a2n(abuf, sizeof(abuf), *argv); if (len < 0) return -1; addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len); } else if (matches(*argv, "broadcast") == 0 || strcmp(*argv, "brd") == 0) { NEXT_ARG(); len = ll_addr_a2n(abuf, sizeof(abuf), *argv); if (len < 0) return -1; addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len); } else if (matches(*argv, "txqueuelen") == 0 || strcmp(*argv, "qlen") == 0 || matches(*argv, "txqlen") == 0) { NEXT_ARG(); if (qlen != -1) duparg("txqueuelen", *argv); if (get_integer(&qlen, *argv, 0)) invarg("Invalid \"txqueuelen\" value\n", *argv); addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4); } else if (strcmp(*argv, "mtu") == 0) { NEXT_ARG(); if (mtu != -1) duparg("mtu", *argv); if (get_integer(&mtu, *argv, 0)) invarg("Invalid \"mtu\" value\n", *argv); addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4); } else if (strcmp(*argv, "netns") == 0) { NEXT_ARG(); if (netns != -1) duparg("netns", *argv); if ((netns = get_netns_fd(*argv)) >= 0) addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4); else if (get_integer(&netns, *argv, 0) == 0) addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4); else invarg("Invalid \"netns\" value\n", *argv); } else if (strcmp(*argv, "multicast") == 0) { NEXT_ARG(); req->i.ifi_change |= IFF_MULTICAST; if (strcmp(*argv, "on") == 0) { req->i.ifi_flags |= IFF_MULTICAST; } else if (strcmp(*argv, "off") == 0) { req->i.ifi_flags &= ~IFF_MULTICAST; } else return on_off("multicast"); } else if (strcmp(*argv, "allmulticast") == 0) { NEXT_ARG(); req->i.ifi_change |= IFF_ALLMULTI; if (strcmp(*argv, "on") == 0) { req->i.ifi_flags |= IFF_ALLMULTI; } else if (strcmp(*argv, "off") == 0) { req->i.ifi_flags &= ~IFF_ALLMULTI; } else return on_off("allmulticast"); } else if (strcmp(*argv, "promisc") == 0) { NEXT_ARG(); req->i.ifi_change |= IFF_PROMISC; if (strcmp(*argv, "on") == 0) { req->i.ifi_flags |= IFF_PROMISC; } else if (strcmp(*argv, "off") == 0) { req->i.ifi_flags &= ~IFF_PROMISC; } else return on_off("promisc"); } else if (strcmp(*argv, "trailers") == 0) { NEXT_ARG(); req->i.ifi_change |= IFF_NOTRAILERS; if (strcmp(*argv, "off") == 0) { req->i.ifi_flags |= IFF_NOTRAILERS; } else if (strcmp(*argv, "on") == 0) { req->i.ifi_flags &= ~IFF_NOTRAILERS; } else return on_off("trailers"); } else if (strcmp(*argv, "arp") == 0) { NEXT_ARG(); req->i.ifi_change |= IFF_NOARP; if (strcmp(*argv, "on") == 0) { req->i.ifi_flags &= ~IFF_NOARP; } else if (strcmp(*argv, "off") == 0) { req->i.ifi_flags |= IFF_NOARP; } else return on_off("noarp"); } else if (strcmp(*argv, "vf") == 0) { struct rtattr *vflist; NEXT_ARG(); if (get_integer(&vf, *argv, 0)) { invarg("Invalid \"vf\" value\n", *argv); } vflist = addattr_nest(&req->n, sizeof(*req), IFLA_VFINFO_LIST); len = iplink_parse_vf(vf, &argc, &argv, req); if (len < 0) return -1; addattr_nest_end(&req->n, vflist); } else if (matches(*argv, "master") == 0) { int ifindex; NEXT_ARG(); ifindex = ll_name_to_index(*argv); if (!ifindex) invarg("Device does not exist\n", *argv); addattr_l(&req->n, sizeof(*req), IFLA_MASTER, &ifindex, 4); } else if (matches(*argv, "nomaster") == 0) { int ifindex = 0; addattr_l(&req->n, sizeof(*req), IFLA_MASTER, &ifindex, 4); } else if (matches(*argv, "dynamic") == 0) { NEXT_ARG(); req->i.ifi_change |= IFF_DYNAMIC; if (strcmp(*argv, "on") == 0) { req->i.ifi_flags |= IFF_DYNAMIC; } else if (strcmp(*argv, "off") == 0) { req->i.ifi_flags &= ~IFF_DYNAMIC; } else return on_off("dynamic"); } else if (matches(*argv, "type") == 0) { NEXT_ARG(); *type = *argv; argc--; argv++; break; } else if (matches(*argv, "alias") == 0) { NEXT_ARG(); addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS, *argv, strlen(*argv)); argc--; argv++; break; } else if (strcmp(*argv, "group") == 0) { NEXT_ARG(); if (*group != -1) duparg("group", *argv); if (rtnl_group_a2n(group, *argv)) invarg("Invalid \"group\" value\n", *argv); } else if (strcmp(*argv, "mode") == 0) { int mode; NEXT_ARG(); mode = get_link_mode(*argv); if (mode < 0) invarg("Invalid link mode\n", *argv); addattr8(&req->n, sizeof(*req), IFLA_LINKMODE, mode); } else if (strcmp(*argv, "state") == 0) { int state; NEXT_ARG(); state = get_operstate(*argv); if (state < 0) invarg("Invalid operstate\n", *argv); addattr8(&req->n, sizeof(*req), IFLA_OPERSTATE, state); } else { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); } if (matches(*argv, "help") == 0) usage(); if (*dev) duparg2("dev", *argv); *dev = *argv; } argc--; argv++; } return ret - argc; }
int do_show_or_flush(int argc, char **argv, int flush) { char *filter_dev = NULL; int state_given = 0; ipneigh_reset_filter(); if (!filter.family) filter.family = preferred_family; if (flush) { if (argc <= 0) { fprintf(stderr, "Flush requires arguments.\n"); return -1; } filter.state = ~(NUD_PERMANENT|NUD_NOARP); } else filter.state = 0xFF & ~NUD_NOARP; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); if (filter_dev) duparg("dev", *argv); filter_dev = *argv; } else if (strcmp(*argv, "unused") == 0) { filter.unused_only = 1; } else if (strcmp(*argv, "nud") == 0) { unsigned state; NEXT_ARG(); if (!state_given) { state_given = 1; filter.state = 0; } if (nud_state_a2n(&state, *argv)) { if (strcmp(*argv, "all") != 0) invarg("nud state is bad", *argv); state = ~0; if (flush) state &= ~NUD_NOARP; } if (state == 0) state = 0x100; filter.state |= state; } else { if (strcmp(*argv, "to") == 0) { NEXT_ARG(); } if (matches(*argv, "help") == 0) usage(); get_prefix(&filter.pfx, *argv, filter.family); if (filter.family == AF_UNSPEC) filter.family = filter.pfx.family; } argc--; argv++; } ll_init_map(&rth); if (filter_dev) { if ((filter.index = ll_name_to_index(filter_dev)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", filter_dev); return -1; } } if (flush) { int round = 0; static char flushb[4096-512]; filter.flushb = flushb; filter.flushp = 0; filter.flushe = sizeof(flushb); filter.state &= ~NUD_FAILED; while (round < MAX_ROUNDS) { if (rtnl_wilddump_request(&rth, filter.family, RTM_GETNEIGH) < 0) { perror("Cannot send dump request"); exit(1); } filter.flushed = 0; if (rtnl_dump_filter(&rth, print_neigh, stdout, NULL, NULL) < 0) { fprintf(stderr, "Flush terminated\n"); exit(1); } if (filter.flushed == 0) { if (show_stats) { if (round == 0) printf("Nothing to flush.\n"); else printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":""); } fflush(stdout); return 0; } round++; if (flush_update() < 0) exit(1); if (show_stats) { printf("\n*** Round %d, deleting %d entries ***\n", round, filter.flushed); fflush(stdout); } } printf("*** Flush not complete bailing out after %d rounds\n", MAX_ROUNDS); return 1; } if (rtnl_wilddump_request(&rth, filter.family, RTM_GETNEIGH) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(&rth, print_neigh, stdout, NULL, NULL) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } return 0; }
static int do_tunnels_list(struct ip6_tnl_parm *p) { char buf[512]; int err = -1; FILE *fp = fopen("/proc/net/dev", "r"); if (fp == NULL) { perror("fopen"); goto end; } /* skip two lines at the begenning of the file */ if (!fgets(buf, sizeof(buf), fp) || !fgets(buf, sizeof(buf), fp)) { fprintf(stderr, "/proc/net/dev read error\n"); return -1; } while (fgets(buf, sizeof(buf), fp) != NULL) { char name[IFNAMSIZ]; int index, type; unsigned long rx_bytes, rx_packets, rx_errs, rx_drops, rx_fifo, rx_frame, tx_bytes, tx_packets, tx_errs, tx_drops, tx_fifo, tx_colls, tx_carrier, rx_multi; struct ip6_tnl_parm p1; char *ptr; buf[sizeof(buf) - 1] = '\0'; if ((ptr = strchr(buf, ':')) == NULL || (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) { fprintf(stderr, "Wrong format for /proc/net/dev. Giving up.\n"); goto end; } if (sscanf(ptr, "%ld%ld%ld%ld%ld%ld%ld%*d%ld%ld%ld%ld%ld%ld%ld", &rx_bytes, &rx_packets, &rx_errs, &rx_drops, &rx_fifo, &rx_frame, &rx_multi, &tx_bytes, &tx_packets, &tx_errs, &tx_drops, &tx_fifo, &tx_colls, &tx_carrier) != 14) continue; if (p->name[0] && strcmp(p->name, name)) continue; index = ll_name_to_index(name); if (index == 0) continue; type = ll_index_to_type(index); if (type == -1) { fprintf(stderr, "Failed to get type of \"%s\"\n", name); continue; } if (type != ARPHRD_TUNNEL6) continue; memset(&p1, 0, sizeof(p1)); ip6_tnl_parm_init(&p1, 0); strcpy(p1.name, name); p1.link = ll_name_to_index(p1.name); if (p1.link == 0) continue; if (tnl_get_ioctl(p1.name, &p1)) continue; if (!ip6_tnl_parm_match(p, &p1)) continue; print_tunnel(&p1); if (show_stats) { printf("%s", _SL_); printf("RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts%s", _SL_); printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-8ld%s", rx_packets, rx_bytes, rx_errs, rx_frame, rx_fifo, rx_multi, _SL_); printf("TX: Packets Bytes Errors DeadLoop NoRoute NoBufs%s", _SL_); printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-6ld", tx_packets, tx_bytes, tx_errs, tx_colls, tx_carrier, tx_drops); } printf("\n"); } err = 0; end: if (fp) fclose(fp); return err; }