static int multiq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { struct tc_multiq_qopt opt; if (argc > 0) { if (strcmp(*argv, "help") == 0) { explain(); return -1; } else { fprintf(stderr, "What is \"%s\"?\n", *argv); explain(); return -1; } argc--; argv++; } addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)); return 0; }
static int ingress_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { if (argc > 0) { while (argc > 0) { if (strcmp(*argv, "handle") == 0) { NEXT_ARG(); argc--; argv++; } else { fprintf(stderr, "What is \"%s\"?\n", *argv); explain(); return -1; } } } addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); return 0; }
int genl_resolve_family(struct rtnl_handle *grth, const char *family) { GENL_REQUEST(req, 1024, GENL_ID_CTRL, 0, 0, CTRL_CMD_GETFAMILY, NLM_F_REQUEST); struct nlmsghdr *answer; int fnum; addattr_l(&req.n, sizeof(req), CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1); if (rtnl_talk(grth, &req.n, &answer) < 0) { fprintf(stderr, "Error talking to the kernel\n"); return -2; } fnum = genl_parse_getfamily(answer); free(answer); return fnum; }
void TunManager::addRemoveTable(int ifIdx, RouterID rid, bool add) { // We just store default routes (one for IPv4 and one for IPv6) in each route // table. struct { struct nlmsghdr n; struct rtmsg r; char buf[256]; } req; const folly::IPAddress addrs[] = { IPAddress{"0.0.0.0"}, // v4 default IPAddress{"::0"}, // v6 default }; for (const auto& addr : addrs) { memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; if (add) { req.n.nlmsg_type = RTM_NEWROUTE; req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_REPLACE; } else { req.n.nlmsg_type = RTM_DELROUTE; } req.r.rtm_family = addr.family(); req.r.rtm_table = getTableId(rid); req.r.rtm_scope = RT_SCOPE_NOWHERE; req.r.rtm_protocol = RTPROT_FBOSS; req.r.rtm_scope = RT_SCOPE_UNIVERSE; req.r.rtm_type = RTN_UNICAST; req.r.rtm_dst_len = 0; // default route, /0 addattr_l(&req.n, sizeof(req), RTA_DST, addr.bytes(), addr.byteCount()); addattr32(&req.n, sizeof(req), RTA_OIF, ifIdx); auto ret = rtnl_talk(&rth_, &req.n, 0, 0, nullptr); sysCheckError(ret, "Failed to ", add ? "add" : "remove", " default route ", addr, " @ index ", ifIdx, " in table ", getTableId(rid), " for router ", rid); LOG(INFO) << (add ? "Added" : "Removed") << " default route " << addr << " @ index " << ifIdx << " in table " << getTableId(rid) << " for router " << rid; } }
/* Utility functions */ static int add_addr2req(struct nlmsghdr *n, int maxlen, int type, ip_address_t *ip_address) { void *addr; int alen; if (!ip_address) return -1; if (IP_IS6(ip_address)) { addr = (void *) &ip_address->u.sin6_addr; alen = sizeof(ip_address->u.sin6_addr); } else { addr = (void *) &ip_address->u.sin.sin_addr; alen = sizeof(ip_address->u.sin.sin_addr); } return addattr_l(n, maxlen, type, addr, alen); }
static int wrr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { struct tc_sfq_qopt opt; memset(&opt, 0, sizeof(opt)); while (argc > 0) { /* if (strcmp(*argv, "quantum") == 0) { NEXT_ARG(); if (get_size(&opt.quantum, *argv)) { fprintf(stderr, "Illegal \"limit\"\n"); return -1; } ok++; } else if (strcmp(*argv, "perturb") == 0) { NEXT_ARG(); if (get_integer(&opt.perturb_period, *argv, 0)) { fprintf(stderr, "Illegal \"perturb\"\n"); return -1; } ok++; } else*/ if (strcmp(*argv, "help") == 0) { explain(); return -1; } else { fprintf(stderr, "What is \"%s\"?\n", *argv); explain(); return -1; } argc--; argv++; } addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)); return 0; }
static int qfq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { struct rtattr *tail; __u32 tmp; tail = NLMSG_TAIL(n); addattr_l(n, 4096, TCA_OPTIONS, NULL, 0); while (argc > 0) { if (matches(*argv, "weight") == 0) { NEXT_ARG(); if (get_u32(&tmp, *argv, 10)) { explain1("weight"); return -1; } addattr32(n, 4096, TCA_QFQ_WEIGHT, tmp); } else if (matches(*argv, "maxpkt") == 0) { NEXT_ARG(); if (get_u32(&tmp, *argv, 10)) { explain1("maxpkt"); return -1; } addattr32(n, 4096, TCA_QFQ_LMAX, tmp); } else if (strcmp(*argv, "help") == 0) { explain_class(); return -1; } else { fprintf(stderr, "What is \"%s\"?\n", *argv); explain_class(); return -1; } argc--; argv++; } tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail; return 0; }
bool set_ip4(int iface_index, uint32_t address, uint8_t network) { bool is_success = false; int ret; struct { struct nlmsghdr nh; struct ifaddrmsg ip; char buf[256]; } req; struct rtnl_handle rth = { .fd = -1 }; uint32_t *ip_data; ret = rtnl_open(&rth, 0); if(ret < 0) { trace(LOG_ERR, "failed to open RTNL socket (code %d)", ret); goto error; } ip_data = calloc(8, sizeof(uint32_t)); if(ip_data == NULL) { trace(LOG_ERR, "failed to allocate memory for setting IPv4 address"); goto close_rtnl; } ip_data[0] = address; /* initialize netlink request */ memset(&req, 0, sizeof(req)); req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; req.nh.nlmsg_type = RTM_NEWADDR; /* ifaddrmsg info */ req.ip.ifa_family = AF_INET; /* IPv4 */ req.ip.ifa_prefixlen = network; req.ip.ifa_index = iface_index; addattr_l(&req.nh, sizeof(req), IFA_LOCAL, ip_data, 4); addattr_l(&req.nh, sizeof(req), IFA_ADDRESS, ip_data, 4); /* GOGOGO */ #if RTNL_TALK_PARAMS == 5 ret = rtnl_talk(&rth, &req.nh, 0, 0, NULL); #elif RTNL_TALK_PARAMS == 7 ret = rtnl_talk(&rth, &req.nh, 0, 0, NULL, NULL, NULL); #else # error "unsupported version of rtnl_talk()" #endif if(ret < 0) { trace(LOG_ERR, "failed to set IPv4 address %u.%u.%u.%u/%u (code %d)", (ntohl(address) >> 24) & 0xff, (ntohl(address) >> 16) & 0xff, (ntohl(address) >> 8) & 0xff, (ntohl(address) >> 0) & 0xff, network, ret); goto free_ip_data; } is_success = true; free_ip_data: free(ip_data); close_rtnl: rtnl_close(&rth); error: return is_success; }
static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n) { int family = strcmp(qu->id, "rsvp") == 0 ? AF_INET : AF_INET6; struct tc_rsvp_pinfo pinfo; struct tc_police tp; struct tcmsg *t = NLMSG_DATA(n); int pinfo_ok = 0; struct rtattr *tail; memset(&pinfo, 0, sizeof(pinfo)); memset(&tp, 0, sizeof(tp)); if (handle) { if (get_u32(&t->tcm_handle, handle, 0)) { my_printf("Illegal \"handle\"\n"); return -1; } } if (argc == 0) return 0; tail = NLMSG_TAIL(n); addattr_l(n, 4096, TCA_OPTIONS, NULL, 0); while (argc > 0) { if (matches(*argv, "session") == 0) { inet_prefix addr; NEXT_ARG(); if (get_addr_and_pi(&argc, &argv, &addr, &pinfo, 1, family)) { my_printf("Illegal \"session\"\n"); return -1; } addattr_l(n, 4096, TCA_RSVP_DST, &addr.data, addr.bytelen); if (pinfo.dpi.mask || pinfo.protocol) pinfo_ok++; continue; } else if (matches(*argv, "sender") == 0 || matches(*argv, "flowspec") == 0) { inet_prefix addr; NEXT_ARG(); if (get_addr_and_pi(&argc, &argv, &addr, &pinfo, 0, family)) { my_printf("Illegal \"sender\"\n"); return -1; } addattr_l(n, 4096, TCA_RSVP_SRC, &addr.data, addr.bytelen); if (pinfo.spi.mask || pinfo.protocol) pinfo_ok++; continue; } else if (matches("ipproto", *argv) == 0) { int num; NEXT_ARG(); num = inet_proto_a2n(*argv); if (num < 0) { my_printf("Illegal \"ipproto\"\n"); return -1; } pinfo.protocol = num; pinfo_ok++; } else if (matches(*argv, "classid") == 0 || strcmp(*argv, "flowid") == 0) { unsigned handle; NEXT_ARG(); if (get_tc_classid(&handle, *argv)) { my_printf("Illegal \"classid\"\n"); return -1; } addattr_l(n, 4096, TCA_RSVP_CLASSID, &handle, 4); } else if (strcmp(*argv, "tunnelid") == 0) { unsigned tid; NEXT_ARG(); if (get_unsigned(&tid, *argv, 0)) { my_printf("Illegal \"tunnelid\"\n"); return -1; } pinfo.tunnelid = tid; pinfo_ok++; } else if (strcmp(*argv, "tunnel") == 0) { unsigned tid; NEXT_ARG(); if (get_unsigned(&tid, *argv, 0)) { my_printf("Illegal \"tunnel\"\n"); return -1; } addattr_l(n, 4096, TCA_RSVP_CLASSID, &tid, 4); NEXT_ARG(); if (strcmp(*argv, "skip") == 0) { NEXT_ARG(); } if (get_unsigned(&tid, *argv, 0)) { my_printf("Illegal \"skip\"\n"); return -1; } pinfo.tunnelhdr = tid; pinfo_ok++; } else if (matches(*argv, "police") == 0) { NEXT_ARG(); if (parse_police(&argc, &argv, TCA_RSVP_POLICE, n)) { my_printf("Illegal \"police\"\n"); return -1; } continue; } else if (strcmp(*argv, "help") == 0) { explain(); return -1; } else { my_printf("What is \"%s\"?\n", *argv); explain(); return -1; } argc--; argv++; } if (pinfo_ok) addattr_l(n, 4096, TCA_RSVP_PINFO, &pinfo, sizeof(pinfo)); tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; return 0; }
static int fdb_modify(int cmd, int flags, int argc, char **argv) { struct { struct nlmsghdr n; struct ndmsg ndm; char buf[256]; } req; char *addr = NULL; char *d = NULL; char abuf[ETH_ALEN]; int dst_ok = 0; 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 = PF_BRIDGE; req.ndm.ndm_state = NUD_NOARP; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); d = *argv; } else if (strcmp(*argv, "dst") == 0) { NEXT_ARG(); if (dst_ok) duparg2("dst", *argv); get_addr(&dst, *argv, preferred_family); dst_ok = 1; } else if (strcmp(*argv, "self") == 0) { req.ndm.ndm_flags |= NTF_SELF; } else if (matches(*argv, "master") == 0) { req.ndm.ndm_flags |= NTF_MASTER; } else if (matches(*argv, "local") == 0|| matches(*argv, "permanent") == 0) { req.ndm.ndm_state |= NUD_PERMANENT; } else if (matches(*argv, "temp") == 0) { req.ndm.ndm_state |= NUD_REACHABLE; } else { if (strcmp(*argv, "to") == 0) { NEXT_ARG(); } if (matches(*argv, "help") == 0) usage(); if (addr) duparg2("to", *argv); addr = *argv; } argc--; argv++; } if (d == NULL || addr == NULL) { fprintf(stderr, "Device and address are required arguments.\n"); exit(-1); } /* Assume self */ if (!(req.ndm.ndm_flags&(NTF_SELF|NTF_MASTER))) req.ndm.ndm_flags |= NTF_SELF; /* Assume permanent */ if (!(req.ndm.ndm_state&(NUD_PERMANENT|NUD_REACHABLE))) req.ndm.ndm_state |= NUD_PERMANENT; if (sscanf(addr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", abuf, abuf+1, abuf+2, abuf+3, abuf+4, abuf+5) != 6) { fprintf(stderr, "Invalid mac address %s\n", addr); exit(-1); } addattr_l(&req.n, sizeof(req), NDA_LLADDR, abuf, ETH_ALEN); if (dst_ok) addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen); req.ndm.ndm_ifindex = ll_name_to_index(d); if (req.ndm.ndm_ifindex == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return -1; } if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) exit(2); return 0; }
/* Return value becomes exitcode. It's okay to not return at all */ static int ipaddr_modify(int cmd, int argc, char **argv) { static const char option[] ALIGN1 = "peer\0""remote\0""broadcast\0""brd\0" "anycast\0""scope\0""dev\0""label\0""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; bool 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_strings(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 && strncmp(d, l, strlen(d)) != 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_and_die("broadcast can be set only for IPv4 addresses"); } 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); xrtnl_open(&rth); ll_init_map(&rth); req.ifa.ifa_index = xll_name_to_index(d); if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) return 2; return 0; }
int parse_gact(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; int action = TC_POLICE_RECLASSIFY; struct tc_gact p; #ifdef CONFIG_GACT_PROB int rd = 0; struct tc_gact_p pp; #endif struct rtattr *tail; memset(&p, 0, sizeof (p)); p.action = TC_POLICE_RECLASSIFY; if (argc < 0) return -1; if (matches(*argv, "gact") == 0) { ok++; } else { action = get_act(&argv); if (action != -10) { p.action = action; ok++; } else { explain(); return action; } } if (ok) { argc--; argv++; } #ifdef CONFIG_GACT_PROB if (ok && argc > 0) { if (matches(*argv, "random") == 0) { rd = 1; NEXT_ARG(); if (matches(*argv, "netrand") == 0) { NEXT_ARG(); pp.ptype = PGACT_NETRAND; } else if (matches(*argv, "determ") == 0) { NEXT_ARG(); pp.ptype = PGACT_DETERM; } else { fprintf(stderr, "Illegal \"random type\"\n"); return -1; } action = get_act(&argv); if (action != -10) { /* FIXME */ pp.paction = action; } else { explain(); return -1; } argc--; argv++; if (get_u16(&pp.pval, *argv, 10)) { fprintf(stderr, "Illegal probability val 0x%x\n",pp.pval); return -1; } if (pp.pval > 10000) { fprintf(stderr, "Illegal probability val 0x%x\n",pp.pval); return -1; } argc--; argv++; } } #endif if (argc > 0) { if (matches(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&p.index, *argv, 10)) { fprintf(stderr, "Illegal \"index\"\n"); return -1; } argc--; argv++; ok++; } } if (!ok) return -1; tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, tca_id, NULL, 0); addattr_l(n, MAX_MSG, TCA_GACT_PARMS, &p, sizeof (p)); #ifdef CONFIG_GACT_PROB if (rd) { addattr_l(n, MAX_MSG, TCA_GACT_PROB, &pp, sizeof (pp)); } #endif tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; *argc_p = argc; *argv_p = argv; return 0; }
int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { struct { struct tc_pedit_sel sel; struct tc_pedit_key keys[MAX_OFFS]; } sel; int argc = *argc_p; char **argv = *argv_p; int ok = 0, iok = 0; struct rtattr *tail; memset(&sel, 0, sizeof(sel)); while (argc > 0) { if (pedit_debug > 1) fprintf(stderr, "while pedit (%d:%s)\n",argc, *argv); if (matches(*argv, "pedit") == 0) { NEXT_ARG(); ok++; continue; } else if (matches(*argv, "help") == 0) { usage(); } else if (matches(*argv, "munge") == 0) { if (!ok) { fprintf(stderr, "Illegal pedit construct (%s) \n", *argv); explain(); return -1; } NEXT_ARG(); if (parse_munge(&argc, &argv,&sel.sel)) { fprintf(stderr, "Illegal pedit construct (%s) \n", *argv); explain(); return -1; } ok++; } else { break; } } if (!ok) { explain(); return -1; } if (argc) { if (matches(*argv, "reclassify") == 0) { sel.sel.action = TC_ACT_RECLASSIFY; NEXT_ARG(); } else if (matches(*argv, "pipe") == 0) { sel.sel.action = TC_ACT_PIPE; NEXT_ARG(); } else if (matches(*argv, "drop") == 0 || matches(*argv, "shot") == 0) { sel.sel.action = TC_ACT_SHOT; NEXT_ARG(); } else if (matches(*argv, "continue") == 0) { sel.sel.action = TC_ACT_UNSPEC; NEXT_ARG(); } else if (matches(*argv, "pass") == 0) { sel.sel.action = TC_ACT_OK; NEXT_ARG(); } } if (argc) { if (matches(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&sel.sel.index, *argv, 10)) { fprintf(stderr, "Pedit: Illegal \"index\"\n"); return -1; } argc--; argv++; iok++; } } tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, tca_id, NULL, 0); addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS,&sel, sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_pedit_key)); tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; *argc_p = argc; *argv_p = argv; return 0; }
static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { struct { struct nlmsghdr n; struct ifinfomsg i; char buf[2048]; } req; struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1]; int len; __u32 link = 0; __u32 laddr = 0; __u32 raddr = 0; __u8 ttl = 0; __u8 tos = 0; __u8 pmtudisc = 1; __u16 iflags = 0; __u8 proto = 0; struct in6_addr ip6rdprefix; __u16 ip6rdprefixlen = 0; __u32 ip6rdrelayprefix = 0; __u16 ip6rdrelayprefixlen = 0; memset(&ip6rdprefix, 0, sizeof(ip6rdprefix)); if (!(n->nlmsg_flags & NLM_F_CREATE)) { memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETLINK; req.i.ifi_family = preferred_family; req.i.ifi_index = ifi->ifi_index; if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) { get_failed: fprintf(stderr, "Failed to get existing tunnel info.\n"); return -1; } len = req.n.nlmsg_len; len -= NLMSG_LENGTH(sizeof(*ifi)); if (len < 0) goto get_failed; parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len); if (!tb[IFLA_LINKINFO]) goto get_failed; parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); if (!linkinfo[IFLA_INFO_DATA]) goto get_failed; parse_rtattr_nested(iptuninfo, IFLA_IPTUN_MAX, linkinfo[IFLA_INFO_DATA]); if (iptuninfo[IFLA_IPTUN_LOCAL]) laddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LOCAL]); if (iptuninfo[IFLA_IPTUN_REMOTE]) raddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_REMOTE]); if (iptuninfo[IFLA_IPTUN_TTL]) ttl = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TTL]); if (iptuninfo[IFLA_IPTUN_TOS]) tos = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TOS]); if (iptuninfo[IFLA_IPTUN_PMTUDISC]) pmtudisc = rta_getattr_u8(iptuninfo[IFLA_IPTUN_PMTUDISC]); if (iptuninfo[IFLA_IPTUN_FLAGS]) iflags = rta_getattr_u16(iptuninfo[IFLA_IPTUN_FLAGS]); if (iptuninfo[IFLA_IPTUN_LINK]) link = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LINK]); if (iptuninfo[IFLA_IPTUN_PROTO]) proto = rta_getattr_u8(iptuninfo[IFLA_IPTUN_PROTO]); if (iptuninfo[IFLA_IPTUN_6RD_PREFIX]) memcpy(&ip6rdprefix, RTA_DATA(iptuninfo[IFLA_IPTUN_6RD_PREFIX]), sizeof(laddr)); if (iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]) ip6rdprefixlen = rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]); if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]) ip6rdrelayprefix = rta_getattr_u32(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]); if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) ip6rdrelayprefixlen = rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]); } while (argc > 0) { if (strcmp(*argv, "remote") == 0) { NEXT_ARG(); if (strcmp(*argv, "any")) raddr = get_addr32(*argv); else raddr = 0; } else if (strcmp(*argv, "local") == 0) { NEXT_ARG(); if (strcmp(*argv, "any")) laddr = get_addr32(*argv); else laddr = 0; } else if (matches(*argv, "dev") == 0) { NEXT_ARG(); link = if_nametoindex(*argv); if (link == 0) invarg("\"dev\" is invalid", *argv); } else if (strcmp(*argv, "ttl") == 0 || strcmp(*argv, "hoplimit") == 0) { NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) { if (get_u8(&ttl, *argv, 0)) invarg("invalid TTL\n", *argv); } else ttl = 0; } else if (strcmp(*argv, "tos") == 0 || strcmp(*argv, "tclass") == 0 || matches(*argv, "dsfield") == 0) { __u32 uval; NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) { if (rtnl_dsfield_a2n(&uval, *argv)) invarg("bad TOS value", *argv); tos = uval; } else tos = 1; } else if (strcmp(*argv, "nopmtudisc") == 0) { pmtudisc = 0; } else if (strcmp(*argv, "pmtudisc") == 0) { pmtudisc = 1; } else if (strcmp(lu->id, "sit") == 0 && strcmp(*argv, "isatap") == 0) { iflags |= SIT_ISATAP; } else if (strcmp(lu->id, "sit") == 0 && strcmp(*argv, "mode") == 0) { NEXT_ARG(); if (strcmp(*argv, "ipv6/ipv4") == 0 || strcmp(*argv, "ip6ip") == 0) proto = IPPROTO_IPV6; else if (strcmp(*argv, "ipv4/ipv4") == 0 || strcmp(*argv, "ipip") == 0 || strcmp(*argv, "ip4ip4") == 0) proto = IPPROTO_IPIP; else if (strcmp(*argv, "any/ipv4") == 0 || strcmp(*argv, "any") == 0) proto = 0; else invarg("Cannot guess tunnel mode.", *argv); } else if (strcmp(*argv, "6rd-prefix") == 0) { inet_prefix prefix; NEXT_ARG(); if (get_prefix(&prefix, *argv, AF_INET6)) invarg("invalid 6rd_prefix\n", *argv); memcpy(&ip6rdprefix, prefix.data, 16); ip6rdprefixlen = prefix.bitlen; } else if (strcmp(*argv, "6rd-relay_prefix") == 0) { inet_prefix prefix; NEXT_ARG(); if (get_prefix(&prefix, *argv, AF_INET)) invarg("invalid 6rd-relay_prefix\n", *argv); memcpy(&ip6rdrelayprefix, prefix.data, 4); ip6rdrelayprefixlen = prefix.bitlen; } else if (strcmp(*argv, "6rd-reset") == 0) { inet_prefix prefix; get_prefix(&prefix, "2002::", AF_INET6); memcpy(&ip6rdprefix, prefix.data, 16); ip6rdprefixlen = 16; ip6rdrelayprefix = 0; ip6rdrelayprefixlen = 0; } else usage(strcmp(lu->id, "sit") == 0); argc--, argv++; } if (ttl && pmtudisc == 0) { fprintf(stderr, "ttl != 0 and nopmtudisc are incompatible\n"); exit(-1); } addattr32(n, 1024, IFLA_IPTUN_LINK, link); addattr32(n, 1024, IFLA_IPTUN_LOCAL, laddr); addattr32(n, 1024, IFLA_IPTUN_REMOTE, raddr); addattr8(n, 1024, IFLA_IPTUN_TTL, ttl); addattr8(n, 1024, IFLA_IPTUN_TOS, tos); addattr8(n, 1024, IFLA_IPTUN_PMTUDISC, pmtudisc); if (strcmp(lu->id, "sit") == 0) { addattr16(n, 1024, IFLA_IPTUN_FLAGS, iflags); addattr8(n, 1024, IFLA_IPTUN_PROTO, proto); if (ip6rdprefixlen) { addattr_l(n, 1024, IFLA_IPTUN_6RD_PREFIX, &ip6rdprefix, sizeof(ip6rdprefix)); addattr16(n, 1024, IFLA_IPTUN_6RD_PREFIXLEN, ip6rdprefixlen); addattr32(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIX, ip6rdrelayprefix); addattr16(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIXLEN, ip6rdrelayprefixlen); } } return 0; }
static int bond_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { __u8 mode, use_carrier, primary_reselect, fail_over_mac; __u8 xmit_hash_policy, num_peer_notif, all_slaves_active; __u8 lacp_rate, ad_select, tlb_dynamic_lb; __u16 ad_user_port_key, ad_actor_sys_prio; __u32 miimon, updelay, downdelay, arp_interval, arp_validate; __u32 arp_all_targets, resend_igmp, min_links, lp_interval; __u32 packets_per_slave; unsigned ifindex; while (argc > 0) { if (matches(*argv, "mode") == 0) { NEXT_ARG(); if (get_index(mode_tbl, *argv) < 0) invarg("invalid mode", *argv); mode = get_index(mode_tbl, *argv); addattr8(n, 1024, IFLA_BOND_MODE, mode); } else if (matches(*argv, "active_slave") == 0) { NEXT_ARG(); ifindex = if_nametoindex(*argv); if (!ifindex) return -1; addattr32(n, 1024, IFLA_BOND_ACTIVE_SLAVE, ifindex); } else if (matches(*argv, "clear_active_slave") == 0) { addattr32(n, 1024, IFLA_BOND_ACTIVE_SLAVE, 0); } else if (matches(*argv, "miimon") == 0) { NEXT_ARG(); if (get_u32(&miimon, *argv, 0)) invarg("invalid miimon", *argv); addattr32(n, 1024, IFLA_BOND_MIIMON, miimon); } else if (matches(*argv, "updelay") == 0) { NEXT_ARG(); if (get_u32(&updelay, *argv, 0)) invarg("invalid updelay", *argv); addattr32(n, 1024, IFLA_BOND_UPDELAY, updelay); } else if (matches(*argv, "downdelay") == 0) { NEXT_ARG(); if (get_u32(&downdelay, *argv, 0)) invarg("invalid downdelay", *argv); addattr32(n, 1024, IFLA_BOND_DOWNDELAY, downdelay); } else if (matches(*argv, "use_carrier") == 0) { NEXT_ARG(); if (get_u8(&use_carrier, *argv, 0)) invarg("invalid use_carrier", *argv); addattr8(n, 1024, IFLA_BOND_USE_CARRIER, use_carrier); } else if (matches(*argv, "arp_interval") == 0) { NEXT_ARG(); if (get_u32(&arp_interval, *argv, 0)) invarg("invalid arp_interval", *argv); addattr32(n, 1024, IFLA_BOND_ARP_INTERVAL, arp_interval); } else if (matches(*argv, "arp_ip_target") == 0) { struct rtattr * nest = addattr_nest(n, 1024, IFLA_BOND_ARP_IP_TARGET); if (NEXT_ARG_OK()) { NEXT_ARG(); char *targets = strdupa(*argv); char *target = strtok(targets, ","); int i; for(i = 0; target && i < BOND_MAX_ARP_TARGETS; i++) { __u32 addr = get_addr32(target); addattr32(n, 1024, i, addr); target = strtok(NULL, ","); } addattr_nest_end(n, nest); } addattr_nest_end(n, nest); } else if (matches(*argv, "arp_validate") == 0) { NEXT_ARG(); if (get_index(arp_validate_tbl, *argv) < 0) invarg("invalid arp_validate", *argv); arp_validate = get_index(arp_validate_tbl, *argv); addattr32(n, 1024, IFLA_BOND_ARP_VALIDATE, arp_validate); } else if (matches(*argv, "arp_all_targets") == 0) { NEXT_ARG(); if (get_index(arp_all_targets_tbl, *argv) < 0) invarg("invalid arp_all_targets", *argv); arp_all_targets = get_index(arp_all_targets_tbl, *argv); addattr32(n, 1024, IFLA_BOND_ARP_ALL_TARGETS, arp_all_targets); } else if (matches(*argv, "primary") == 0) { NEXT_ARG(); ifindex = if_nametoindex(*argv); if (!ifindex) return -1; addattr32(n, 1024, IFLA_BOND_PRIMARY, ifindex); } else if (matches(*argv, "primary_reselect") == 0) { NEXT_ARG(); if (get_index(primary_reselect_tbl, *argv) < 0) invarg("invalid primary_reselect", *argv); primary_reselect = get_index(primary_reselect_tbl, *argv); addattr8(n, 1024, IFLA_BOND_PRIMARY_RESELECT, primary_reselect); } else if (matches(*argv, "fail_over_mac") == 0) { NEXT_ARG(); if (get_index(fail_over_mac_tbl, *argv) < 0) invarg("invalid fail_over_mac", *argv); fail_over_mac = get_index(fail_over_mac_tbl, *argv); addattr8(n, 1024, IFLA_BOND_FAIL_OVER_MAC, fail_over_mac); } else if (matches(*argv, "xmit_hash_policy") == 0) { NEXT_ARG(); if (get_index(xmit_hash_policy_tbl, *argv) < 0) invarg("invalid xmit_hash_policy", *argv); xmit_hash_policy = get_index(xmit_hash_policy_tbl, *argv); addattr8(n, 1024, IFLA_BOND_XMIT_HASH_POLICY, xmit_hash_policy); } else if (matches(*argv, "resend_igmp") == 0) { NEXT_ARG(); if (get_u32(&resend_igmp, *argv, 0)) invarg("invalid resend_igmp", *argv); addattr32(n, 1024, IFLA_BOND_RESEND_IGMP, resend_igmp); } else if (matches(*argv, "num_grat_arp") == 0 || matches(*argv, "num_unsol_na") == 0) { NEXT_ARG(); if (get_u8(&num_peer_notif, *argv, 0)) invarg("invalid num_grat_arp|num_unsol_na", *argv); addattr8(n, 1024, IFLA_BOND_NUM_PEER_NOTIF, num_peer_notif); } else if (matches(*argv, "all_slaves_active") == 0) { NEXT_ARG(); if (get_u8(&all_slaves_active, *argv, 0)) invarg("invalid all_slaves_active", *argv); addattr8(n, 1024, IFLA_BOND_ALL_SLAVES_ACTIVE, all_slaves_active); } else if (matches(*argv, "min_links") == 0) { NEXT_ARG(); if (get_u32(&min_links, *argv, 0)) invarg("invalid min_links", *argv); addattr32(n, 1024, IFLA_BOND_MIN_LINKS, min_links); } else if (matches(*argv, "lp_interval") == 0) { NEXT_ARG(); if (get_u32(&lp_interval, *argv, 0)) invarg("invalid lp_interval", *argv); addattr32(n, 1024, IFLA_BOND_LP_INTERVAL, lp_interval); } else if (matches(*argv, "packets_per_slave") == 0) { NEXT_ARG(); if (get_u32(&packets_per_slave, *argv, 0)) invarg("invalid packets_per_slave", *argv); addattr32(n, 1024, IFLA_BOND_PACKETS_PER_SLAVE, packets_per_slave); } else if (matches(*argv, "lacp_rate") == 0) { NEXT_ARG(); if (get_index(lacp_rate_tbl, *argv) < 0) invarg("invalid lacp_rate", *argv); lacp_rate = get_index(lacp_rate_tbl, *argv); addattr8(n, 1024, IFLA_BOND_AD_LACP_RATE, lacp_rate); } else if (matches(*argv, "ad_select") == 0) { NEXT_ARG(); if (get_index(ad_select_tbl, *argv) < 0) invarg("invalid ad_select", *argv); ad_select = get_index(ad_select_tbl, *argv); addattr8(n, 1024, IFLA_BOND_AD_SELECT, ad_select); } else if (matches(*argv, "ad_user_port_key") == 0) { NEXT_ARG(); if (get_u16(&ad_user_port_key, *argv, 0)) invarg("invalid ad_user_port_key", *argv); addattr16(n, 1024, IFLA_BOND_AD_USER_PORT_KEY, ad_user_port_key); } else if (matches(*argv, "ad_actor_sys_prio") == 0) { NEXT_ARG(); if (get_u16(&ad_actor_sys_prio, *argv, 0)) invarg("invalid ad_actor_sys_prio", *argv); addattr16(n, 1024, IFLA_BOND_AD_ACTOR_SYS_PRIO, ad_actor_sys_prio); } else if (matches(*argv, "ad_actor_system") == 0) { int len; char abuf[32]; NEXT_ARG(); len = ll_addr_a2n(abuf, sizeof(abuf), *argv); if (len < 0) return -1; addattr_l(n, 1024, IFLA_BOND_AD_ACTOR_SYSTEM, abuf, len); } else if (matches(*argv, "tlb_dynamic_lb") == 0) { NEXT_ARG(); if (get_u8(&tlb_dynamic_lb, *argv, 0)) { invarg("invalid tlb_dynamic_lb", *argv); return -1; } addattr8(n, 1024, IFLA_BOND_TLB_DYNAMIC_LB, tlb_dynamic_lb); } else if (matches(*argv, "help") == 0) { explain(); return -1; } else { fprintf(stderr, "bond: unknown command \"%s\"?\n", *argv); explain(); return -1; } argc--, argv++; } return 0; }
static int parse_connmark(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { struct tc_connmark sel = {}; char **argv = *argv_p; int argc = *argc_p; int ok = 0; struct rtattr *tail; while (argc > 0) { if (matches(*argv, "connmark") == 0) { ok = 1; argc--; argv++; } else if (matches(*argv, "help") == 0) { usage(); } else { break; } } if (!ok) { explain(); return -1; } if (argc) { if (matches(*argv, "zone") == 0) { NEXT_ARG(); if (get_u16(&sel.zone, *argv, 10)) { fprintf(stderr, "simple: Illegal \"index\"\n"); return -1; } argc--; argv++; } } parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_PIPE); if (argc) { if (matches(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&sel.index, *argv, 10)) { fprintf(stderr, "simple: Illegal \"index\"\n"); return -1; } argc--; argv++; } } tail = addattr_nest(n, MAX_MSG, tca_id); addattr_l(n, MAX_MSG, TCA_CONNMARK_PARMS, &sel, sizeof(sel)); addattr_nest_end(n, tail); *argc_p = argc; *argv_p = argv; return 0; }
static int parse_skbedit(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; struct rtattr *tail; unsigned int tmp; __u16 queue_mapping, ptype; __u32 flags = 0, priority, mark; struct tc_skbedit sel = { 0 }; if (matches(*argv, "skbedit") != 0) return -1; NEXT_ARG(); while (argc > 0) { if (matches(*argv, "queue_mapping") == 0) { flags |= SKBEDIT_F_QUEUE_MAPPING; NEXT_ARG(); if (get_unsigned(&tmp, *argv, 10) || tmp > 65535) { fprintf(stderr, "Illegal queue_mapping\n"); return -1; } queue_mapping = tmp; ok++; } else if (matches(*argv, "priority") == 0) { flags |= SKBEDIT_F_PRIORITY; NEXT_ARG(); if (get_tc_classid(&priority, *argv)) { fprintf(stderr, "Illegal priority\n"); return -1; } ok++; } else if (matches(*argv, "mark") == 0) { flags |= SKBEDIT_F_MARK; NEXT_ARG(); if (get_u32(&mark, *argv, 0)) { fprintf(stderr, "Illegal mark\n"); return -1; } ok++; } else if (matches(*argv, "ptype") == 0) { NEXT_ARG(); if (matches(*argv, "host") == 0) { ptype = PACKET_HOST; } else if (matches(*argv, "broadcast") == 0) { ptype = PACKET_BROADCAST; } else if (matches(*argv, "multicast") == 0) { ptype = PACKET_MULTICAST; } else if (matches(*argv, "otherhost") == 0) { ptype = PACKET_OTHERHOST; } else { fprintf(stderr, "Illegal ptype (%s)\n", *argv); return -1; } flags |= SKBEDIT_F_PTYPE; ok++; } else if (matches(*argv, "help") == 0) { usage(); } else { break; } argc--; argv++; } parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_PIPE); if (argc) { if (matches(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&sel.index, *argv, 10)) { fprintf(stderr, "Pedit: Illegal \"index\"\n"); return -1; } argc--; argv++; ok++; } } if (!ok) { explain(); return -1; } tail = addattr_nest(n, MAX_MSG, tca_id); addattr_l(n, MAX_MSG, TCA_SKBEDIT_PARMS, &sel, sizeof(sel)); if (flags & SKBEDIT_F_QUEUE_MAPPING) addattr_l(n, MAX_MSG, TCA_SKBEDIT_QUEUE_MAPPING, &queue_mapping, sizeof(queue_mapping)); if (flags & SKBEDIT_F_PRIORITY) addattr_l(n, MAX_MSG, TCA_SKBEDIT_PRIORITY, &priority, sizeof(priority)); if (flags & SKBEDIT_F_MARK) addattr_l(n, MAX_MSG, TCA_SKBEDIT_MARK, &mark, sizeof(mark)); if (flags & SKBEDIT_F_PTYPE) addattr_l(n, MAX_MSG, TCA_SKBEDIT_PTYPE, &ptype, sizeof(ptype)); addattr_nest_end(n, tail); *argc_p = argc; *argv_p = argv; return 0; }
static int iprule_modify(int cmd, int argc, char **argv) { int table_ok = 0; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; memset(&req, 0, sizeof(req)); req.n.nlmsg_type = cmd; req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.r.rtm_family = preferred_family; req.r.rtm_protocol = RTPROT_BOOT; req.r.rtm_scope = RT_SCOPE_UNIVERSE; req.r.rtm_table = 0; req.r.rtm_type = RTN_UNSPEC; req.r.rtm_flags = 0; if (cmd == RTM_NEWRULE) { req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; req.r.rtm_type = RTN_UNICAST; } while (argc > 0) { if (strcmp(*argv, "not") == 0) { req.r.rtm_flags |= FIB_RULE_INVERT; } else if (strcmp(*argv, "from") == 0) { inet_prefix dst; NEXT_ARG(); get_prefix(&dst, *argv, req.r.rtm_family); req.r.rtm_src_len = dst.bitlen; addattr_l(&req.n, sizeof(req), FRA_SRC, &dst.data, dst.bytelen); } else if (strcmp(*argv, "to") == 0) { inet_prefix dst; NEXT_ARG(); get_prefix(&dst, *argv, req.r.rtm_family); req.r.rtm_dst_len = dst.bitlen; addattr_l(&req.n, sizeof(req), FRA_DST, &dst.data, dst.bytelen); } else if (matches(*argv, "preference") == 0 || matches(*argv, "order") == 0 || matches(*argv, "priority") == 0) { __u32 pref; NEXT_ARG(); if (get_u32(&pref, *argv, 0)) invarg("preference value is invalid\n", *argv); addattr32(&req.n, sizeof(req), FRA_PRIORITY, pref); } else if (strcmp(*argv, "tos") == 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 (strcmp(*argv, "fwmark") == 0) { char *slash; __u32 fwmark, fwmask; NEXT_ARG(); if ((slash = strchr(*argv, '/')) != NULL) *slash = '\0'; if (get_u32(&fwmark, *argv, 0)) invarg("fwmark value is invalid\n", *argv); addattr32(&req.n, sizeof(req), FRA_FWMARK, fwmark); if (slash) { if (get_u32(&fwmask, slash+1, 0)) invarg("fwmask value is invalid\n", slash+1); addattr32(&req.n, sizeof(req), FRA_FWMASK, fwmask); } } else if (matches(*argv, "realms") == 0) { __u32 realm; NEXT_ARG(); if (get_rt_realms(&realm, *argv)) invarg("invalid realms\n", *argv); addattr32(&req.n, sizeof(req), FRA_FLOW, realm); } else if (matches(*argv, "table") == 0 || strcmp(*argv, "lookup") == 0) { __u32 tid; NEXT_ARG(); if (rtnl_rttable_a2n(&tid, *argv)) invarg("invalid table ID\n", *argv); if (tid < 256) req.r.rtm_table = tid; else { req.r.rtm_table = RT_TABLE_UNSPEC; addattr32(&req.n, sizeof(req), FRA_TABLE, tid); } table_ok = 1; } else if (strcmp(*argv, "dev") == 0 || strcmp(*argv, "iif") == 0) { NEXT_ARG(); addattr_l(&req.n, sizeof(req), FRA_IFNAME, *argv, strlen(*argv)+1); } else if (strcmp(*argv, "nat") == 0 || matches(*argv, "map-to") == 0) { NEXT_ARG(); fprintf(stderr, "Warning: route NAT is deprecated\n"); addattr32(&req.n, sizeof(req), RTA_GATEWAY, get_addr32(*argv)); req.r.rtm_type = RTN_NAT; } else { int type; if (strcmp(*argv, "type") == 0) { NEXT_ARG(); } if (matches(*argv, "help") == 0) usage(); else if (matches(*argv, "goto") == 0) { __u32 target; type = FR_ACT_GOTO; NEXT_ARG(); if (get_u32(&target, *argv, 0)) invarg("invalid target\n", *argv); addattr32(&req.n, sizeof(req), FRA_GOTO, target); } else if (matches(*argv, "nop") == 0) type = FR_ACT_NOP; else if (rtnl_rtntype_a2n(&type, *argv)) invarg("Failed to parse rule type", *argv); req.r.rtm_type = type; table_ok = 1; } argc--; argv++; } if (req.r.rtm_family == AF_UNSPEC) req.r.rtm_family = AF_INET; if (!table_ok && cmd == RTM_NEWRULE) req.r.rtm_table = RT_TABLE_MAIN; if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) return 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 red_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { struct tc_red_qopt opt; unsigned burst = 0; unsigned avpkt = 0; double probability = 0.02; __u64 rate = 0; int wlog; __u8 sbuf[256]; __u32 max_P; struct rtattr *tail; memset(&opt, 0, sizeof(opt)); while (argc > 0) { if (strcmp(*argv, "limit") == 0) { NEXT_ARG(); if (get_size(&opt.limit, *argv)) { fprintf(stderr, "Illegal \"limit\"\n"); return -1; } } else if (strcmp(*argv, "min") == 0) { NEXT_ARG(); if (get_size(&opt.qth_min, *argv)) { fprintf(stderr, "Illegal \"min\"\n"); return -1; } } else if (strcmp(*argv, "max") == 0) { NEXT_ARG(); if (get_size(&opt.qth_max, *argv)) { fprintf(stderr, "Illegal \"max\"\n"); return -1; } } else if (strcmp(*argv, "burst") == 0) { NEXT_ARG(); if (get_unsigned(&burst, *argv, 0)) { fprintf(stderr, "Illegal \"burst\"\n"); return -1; } } else if (strcmp(*argv, "avpkt") == 0) { NEXT_ARG(); if (get_size(&avpkt, *argv)) { fprintf(stderr, "Illegal \"avpkt\"\n"); return -1; } } else if (strcmp(*argv, "probability") == 0) { NEXT_ARG(); if (sscanf(*argv, "%lg", &probability) != 1) { fprintf(stderr, "Illegal \"probability\"\n"); return -1; } } else if (strcmp(*argv, "bandwidth") == 0) { NEXT_ARG(); if (get_rate(&rate, *argv)) { fprintf(stderr, "Illegal \"bandwidth\"\n"); return -1; } } else if (strcmp(*argv, "ecn") == 0) { opt.flags |= TC_RED_ECN; } else if (strcmp(*argv, "harddrop") == 0) { opt.flags |= TC_RED_HARDDROP; } else if (strcmp(*argv, "adaptative") == 0) { opt.flags |= TC_RED_ADAPTATIVE; } else if (strcmp(*argv, "adaptive") == 0) { opt.flags |= TC_RED_ADAPTATIVE; } else if (strcmp(*argv, "help") == 0) { explain(); return -1; } else { fprintf(stderr, "What is \"%s\"?\n", *argv); explain(); return -1; } argc--; argv++; } if (rate == 0) get_rate(&rate, "10Mbit"); if (!opt.limit || !avpkt) { fprintf(stderr, "RED: Required parameter (limit, avpkt) is missing\n"); return -1; } /* Compute default min/max thresholds based on * Sally Floyd's recommendations: * http://www.icir.org/floyd/REDparameters.txt */ if (!opt.qth_max) opt.qth_max = opt.qth_min ? opt.qth_min * 3 : opt.limit / 4; if (!opt.qth_min) opt.qth_min = opt.qth_max / 3; if (!burst) burst = (2 * opt.qth_min + opt.qth_max) / (3 * avpkt); if ((wlog = tc_red_eval_ewma(opt.qth_min, burst, avpkt)) < 0) { fprintf(stderr, "RED: failed to calculate EWMA constant.\n"); return -1; } if (wlog >= 10) fprintf(stderr, "RED: WARNING. Burst %d seems to be too large.\n", burst); opt.Wlog = wlog; if ((wlog = tc_red_eval_P(opt.qth_min, opt.qth_max, probability)) < 0) { fprintf(stderr, "RED: failed to calculate probability.\n"); return -1; } opt.Plog = wlog; if ((wlog = tc_red_eval_idle_damping(opt.Wlog, avpkt, rate, sbuf)) < 0) { fprintf(stderr, "RED: failed to calculate idle damping table.\n"); return -1; } opt.Scell_log = wlog; tail = NLMSG_TAIL(n); addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); addattr_l(n, 1024, TCA_RED_PARMS, &opt, sizeof(opt)); addattr_l(n, 1024, TCA_RED_STAB, sbuf, 256); max_P = probability * pow(2, 32); addattr_l(n, 1024, TCA_RED_MAX_P, &max_P, sizeof(max_P)); tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; return 0; }
static int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { struct m_pedit_sel sel = {}; int argc = *argc_p; char **argv = *argv_p; int ok = 0, iok = 0; struct rtattr *tail; while (argc > 0) { if (pedit_debug > 1) fprintf(stderr, "while pedit (%d:%s)\n", argc, *argv); if (matches(*argv, "pedit") == 0) { NEXT_ARG(); ok++; if (matches(*argv, "ex") == 0) { if (ok > 1) { fprintf(stderr, "'ex' must be before first 'munge'\n"); explain(); return -1; } sel.extended = true; NEXT_ARG(); } continue; } else if (matches(*argv, "help") == 0) { usage(); } else if (matches(*argv, "munge") == 0) { if (!ok) { fprintf(stderr, "Bad pedit construct (%s)\n", *argv); explain(); return -1; } NEXT_ARG(); if (parse_munge(&argc, &argv, &sel)) { fprintf(stderr, "Bad pedit construct (%s)\n", *argv); explain(); return -1; } ok++; } else { break; } } if (!ok) { explain(); return -1; } parse_action_control_dflt(&argc, &argv, &sel.sel.action, false, TC_ACT_OK); if (argc) { if (matches(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&sel.sel.index, *argv, 10)) { fprintf(stderr, "Pedit: Illegal \"index\"\n"); return -1; } argc--; argv++; iok++; } } tail = addattr_nest(n, MAX_MSG, tca_id); if (!sel.extended) { addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS, &sel, sizeof(sel.sel) + sel.sel.nkeys * sizeof(struct tc_pedit_key)); } else { addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS_EX, &sel, sizeof(sel.sel) + sel.sel.nkeys * sizeof(struct tc_pedit_key)); pedit_keys_ex_addattr(&sel, n); } addattr_nest_end(n, tail); *argc_p = argc; *argv_p = argv; return 0; }
static int codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) { unsigned int limit = 0; unsigned int target = 0; unsigned int interval = 0; unsigned int ce_threshold = ~0U; int ecn = -1; struct rtattr *tail; while (argc > 0) { if (strcmp(*argv, "limit") == 0) { NEXT_ARG(); if (get_unsigned(&limit, *argv, 0)) { fprintf(stderr, "Illegal \"limit\"\n"); return -1; } } else if (strcmp(*argv, "target") == 0) { NEXT_ARG(); if (get_time(&target, *argv)) { fprintf(stderr, "Illegal \"target\"\n"); return -1; } } else if (strcmp(*argv, "ce_threshold") == 0) { NEXT_ARG(); if (get_time(&ce_threshold, *argv)) { fprintf(stderr, "Illegal \"ce_threshold\"\n"); return -1; } } else if (strcmp(*argv, "interval") == 0) { NEXT_ARG(); if (get_time(&interval, *argv)) { fprintf(stderr, "Illegal \"interval\"\n"); return -1; } } else if (strcmp(*argv, "ecn") == 0) { ecn = 1; } else if (strcmp(*argv, "noecn") == 0) { ecn = 0; } else if (strcmp(*argv, "help") == 0) { explain(); return -1; } else { fprintf(stderr, "What is \"%s\"?\n", *argv); explain(); return -1; } argc--; argv++; } tail = addattr_nest(n, 1024, TCA_OPTIONS); if (limit) addattr_l(n, 1024, TCA_CODEL_LIMIT, &limit, sizeof(limit)); if (interval) addattr_l(n, 1024, TCA_CODEL_INTERVAL, &interval, sizeof(interval)); if (target) addattr_l(n, 1024, TCA_CODEL_TARGET, &target, sizeof(target)); if (ecn != -1) addattr_l(n, 1024, TCA_CODEL_ECN, &ecn, sizeof(ecn)); if (ce_threshold != ~0U) addattr_l(n, 1024, TCA_CODEL_CE_THRESHOLD, &ce_threshold, sizeof(ce_threshold)); addattr_nest_end(n, tail); return 0; }
static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv) { struct rtnl_handle rth; struct { struct nlmsghdr n; struct xfrm_userpolicy_info xpinfo; char buf[RTA_BUF_SIZE]; } req; char *dirp = NULL; char *selp = NULL; char *ptypep = NULL; struct xfrm_userpolicy_type upt; char tmpls_buf[XFRM_TMPLS_BUF_SIZE]; int tmpls_len = 0; memset(&req, 0, sizeof(req)); memset(&upt, 0, sizeof(upt)); memset(&tmpls_buf, 0, sizeof(tmpls_buf)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpinfo)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.xpinfo.sel.family = preferred_family; req.xpinfo.lft.soft_byte_limit = XFRM_INF; req.xpinfo.lft.hard_byte_limit = XFRM_INF; req.xpinfo.lft.soft_packet_limit = XFRM_INF; req.xpinfo.lft.hard_packet_limit = XFRM_INF; while (argc > 0) { if (strcmp(*argv, "dir") == 0) { if (dirp) duparg("dir", *argv); dirp = *argv; NEXT_ARG(); xfrm_policy_dir_parse(&req.xpinfo.dir, &argc, &argv); } else if (strcmp(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&req.xpinfo.index, *argv, 0)) invarg("\"INDEX\" is invalid", *argv); } else if (strcmp(*argv, "ptype") == 0) { if (ptypep) duparg("ptype", *argv); ptypep = *argv; NEXT_ARG(); xfrm_policy_ptype_parse(&upt.type, &argc, &argv); } else if (strcmp(*argv, "action") == 0) { NEXT_ARG(); if (strcmp(*argv, "allow") == 0) req.xpinfo.action = XFRM_POLICY_ALLOW; else if (strcmp(*argv, "block") == 0) req.xpinfo.action = XFRM_POLICY_BLOCK; else invarg("\"action\" value is invalid\n", *argv); } else if (strcmp(*argv, "priority") == 0) { NEXT_ARG(); if (get_u32(&req.xpinfo.priority, *argv, 0)) invarg("\"PRIORITY\" is invalid", *argv); } else if (strcmp(*argv, "flag") == 0) { NEXT_ARG(); xfrm_policy_flag_parse(&req.xpinfo.flags, &argc, &argv); } else if (strcmp(*argv, "limit") == 0) { NEXT_ARG(); xfrm_lifetime_cfg_parse(&req.xpinfo.lft, &argc, &argv); } else if (strcmp(*argv, "tmpl") == 0) { struct xfrm_user_tmpl *tmpl; if (tmpls_len + sizeof(*tmpl) > sizeof(tmpls_buf)) { fprintf(stderr, "Too many tmpls: buffer overflow\n"); exit(1); } tmpl = (struct xfrm_user_tmpl *)((char *)tmpls_buf + tmpls_len); tmpl->family = preferred_family; tmpl->aalgos = (~(__u32)0); tmpl->ealgos = (~(__u32)0); tmpl->calgos = (~(__u32)0); NEXT_ARG(); xfrm_tmpl_parse(tmpl, &argc, &argv); tmpls_len += sizeof(*tmpl); } else { if (selp) duparg("unknown", *argv); selp = *argv; xfrm_selector_parse(&req.xpinfo.sel, &argc, &argv); if (preferred_family == AF_UNSPEC) preferred_family = req.xpinfo.sel.family; } argc--; argv++; } if (!dirp) { fprintf(stderr, "Not enough information: \"DIR\" is required.\n"); exit(1); } if (ptypep) { addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE, (void *)&upt, sizeof(upt)); } if (tmpls_len > 0) { addattr_l(&req.n, sizeof(req), XFRMA_TMPL, (void *)tmpls_buf, tmpls_len); } if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) exit(1); if (req.xpinfo.sel.family == AF_UNSPEC) req.xpinfo.sel.family = AF_INET; if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) exit(2); rtnl_close(&rth); return 0; }
static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { __u32 val; while (argc > 0) { if (matches(*argv, "forward_delay") == 0) { NEXT_ARG(); if (get_u32(&val, *argv, 0)) invarg("invalid forward_delay", *argv); addattr32(n, 1024, IFLA_BR_FORWARD_DELAY, val); } else if (matches(*argv, "hello_time") == 0) { NEXT_ARG(); if (get_u32(&val, *argv, 0)) invarg("invalid hello_time", *argv); addattr32(n, 1024, IFLA_BR_HELLO_TIME, val); } else if (matches(*argv, "max_age") == 0) { NEXT_ARG(); if (get_u32(&val, *argv, 0)) invarg("invalid max_age", *argv); addattr32(n, 1024, IFLA_BR_MAX_AGE, val); } else if (matches(*argv, "ageing_time") == 0) { NEXT_ARG(); if (get_u32(&val, *argv, 0)) invarg("invalid ageing_time", *argv); addattr32(n, 1024, IFLA_BR_AGEING_TIME, val); } else if (matches(*argv, "stp_state") == 0) { NEXT_ARG(); if (get_u32(&val, *argv, 0)) invarg("invalid stp_state", *argv); addattr32(n, 1024, IFLA_BR_STP_STATE, val); } else if (matches(*argv, "priority") == 0) { __u16 prio; NEXT_ARG(); if (get_u16(&prio, *argv, 0)) invarg("invalid priority", *argv); addattr16(n, 1024, IFLA_BR_PRIORITY, prio); } else if (matches(*argv, "vlan_filtering") == 0) { __u8 vlan_filter; NEXT_ARG(); if (get_u8(&vlan_filter, *argv, 0)) invarg("invalid vlan_filtering", *argv); addattr8(n, 1024, IFLA_BR_VLAN_FILTERING, vlan_filter); } else if (matches(*argv, "vlan_protocol") == 0) { __u16 vlan_proto; NEXT_ARG(); if (ll_proto_a2n(&vlan_proto, *argv)) invarg("invalid vlan_protocol", *argv); addattr16(n, 1024, IFLA_BR_VLAN_PROTOCOL, vlan_proto); } else if (matches(*argv, "group_fwd_mask") == 0) { __u16 fwd_mask; NEXT_ARG(); if (get_u16(&fwd_mask, *argv, 0)) invarg("invalid group_fwd_mask", *argv); addattr16(n, 1024, IFLA_BR_GROUP_FWD_MASK, fwd_mask); } else if (matches(*argv, "group_address") == 0) { char llabuf[32]; int len; NEXT_ARG(); len = ll_addr_a2n(llabuf, sizeof(llabuf), *argv); if (len < 0) return -1; addattr_l(n, 1024, IFLA_BR_GROUP_ADDR, llabuf, len); } else if (matches(*argv, "vlan_default_pvid") == 0) { __u16 default_pvid; NEXT_ARG(); if (get_u16(&default_pvid, *argv, 0)) invarg("invalid vlan_default_pvid", *argv); addattr16(n, 1024, IFLA_BR_VLAN_DEFAULT_PVID, default_pvid); } else if (matches(*argv, "mcast_router") == 0) { __u8 mcast_router; NEXT_ARG(); if (get_u8(&mcast_router, *argv, 0)) invarg("invalid mcast_router", *argv); addattr8(n, 1024, IFLA_BR_MCAST_ROUTER, mcast_router); } else if (matches(*argv, "mcast_snooping") == 0) { __u8 mcast_snoop; NEXT_ARG(); if (get_u8(&mcast_snoop, *argv, 0)) invarg("invalid mcast_snooping", *argv); addattr8(n, 1024, IFLA_BR_MCAST_SNOOPING, mcast_snoop); } else if (matches(*argv, "mcast_query_use_ifaddr") == 0) { __u8 mcast_qui; NEXT_ARG(); if (get_u8(&mcast_qui, *argv, 0)) invarg("invalid mcast_query_use_ifaddr", *argv); addattr8(n, 1024, IFLA_BR_MCAST_QUERY_USE_IFADDR, mcast_qui); } else if (matches(*argv, "mcast_querier") == 0) { __u8 mcast_querier; NEXT_ARG(); if (get_u8(&mcast_querier, *argv, 0)) invarg("invalid mcast_querier", *argv); addattr8(n, 1024, IFLA_BR_MCAST_QUERIER, mcast_querier); } else if (matches(*argv, "mcast_hash_elasticity") == 0) { __u32 mcast_hash_el; NEXT_ARG(); if (get_u32(&mcast_hash_el, *argv, 0)) invarg("invalid mcast_hash_elasticity", *argv); addattr32(n, 1024, IFLA_BR_MCAST_HASH_ELASTICITY, mcast_hash_el); } else if (matches(*argv, "mcast_hash_max") == 0) { __u32 mcast_hash_max; NEXT_ARG(); if (get_u32(&mcast_hash_max, *argv, 0)) invarg("invalid mcast_hash_max", *argv); addattr32(n, 1024, IFLA_BR_MCAST_HASH_MAX, mcast_hash_max); } else if (matches(*argv, "mcast_last_member_count") == 0) { __u32 mcast_lmc; NEXT_ARG(); if (get_u32(&mcast_lmc, *argv, 0)) invarg("invalid mcast_last_member_count", *argv); addattr32(n, 1024, IFLA_BR_MCAST_LAST_MEMBER_CNT, mcast_lmc); } else if (matches(*argv, "mcast_startup_query_count") == 0) { __u32 mcast_sqc; NEXT_ARG(); if (get_u32(&mcast_sqc, *argv, 0)) invarg("invalid mcast_startup_query_count", *argv); addattr32(n, 1024, IFLA_BR_MCAST_STARTUP_QUERY_CNT, mcast_sqc); } else if (matches(*argv, "mcast_last_member_interval") == 0) { __u64 mcast_last_member_intvl; NEXT_ARG(); if (get_u64(&mcast_last_member_intvl, *argv, 0)) invarg("invalid mcast_last_member_interval", *argv); addattr64(n, 1024, IFLA_BR_MCAST_LAST_MEMBER_INTVL, mcast_last_member_intvl); } else if (matches(*argv, "mcast_membership_interval") == 0) { __u64 mcast_membership_intvl; NEXT_ARG(); if (get_u64(&mcast_membership_intvl, *argv, 0)) invarg("invalid mcast_membership_interval", *argv); addattr64(n, 1024, IFLA_BR_MCAST_MEMBERSHIP_INTVL, mcast_membership_intvl); } else if (matches(*argv, "mcast_querier_interval") == 0) { __u64 mcast_querier_intvl; NEXT_ARG(); if (get_u64(&mcast_querier_intvl, *argv, 0)) invarg("invalid mcast_querier_interval", *argv); addattr64(n, 1024, IFLA_BR_MCAST_QUERIER_INTVL, mcast_querier_intvl); } else if (matches(*argv, "mcast_query_interval") == 0) { __u64 mcast_query_intvl; NEXT_ARG(); if (get_u64(&mcast_query_intvl, *argv, 0)) invarg("invalid mcast_query_interval", *argv); addattr64(n, 1024, IFLA_BR_MCAST_QUERY_INTVL, mcast_query_intvl); } else if (!matches(*argv, "mcast_query_response_interval")) { __u64 mcast_query_resp_intvl; NEXT_ARG(); if (get_u64(&mcast_query_resp_intvl, *argv, 0)) invarg("invalid mcast_query_response_interval", *argv); addattr64(n, 1024, IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, mcast_query_resp_intvl); } else if (!matches(*argv, "mcast_startup_query_interval")) { __u64 mcast_startup_query_intvl; NEXT_ARG(); if (get_u64(&mcast_startup_query_intvl, *argv, 0)) invarg("invalid mcast_startup_query_interval", *argv); addattr64(n, 1024, IFLA_BR_MCAST_STARTUP_QUERY_INTVL, mcast_startup_query_intvl); } else if (matches(*argv, "nf_call_iptables") == 0) { __u8 nf_call_ipt; NEXT_ARG(); if (get_u8(&nf_call_ipt, *argv, 0)) invarg("invalid nf_call_iptables", *argv); addattr8(n, 1024, IFLA_BR_NF_CALL_IPTABLES, nf_call_ipt); } else if (matches(*argv, "nf_call_ip6tables") == 0) { __u8 nf_call_ip6t; NEXT_ARG(); if (get_u8(&nf_call_ip6t, *argv, 0)) invarg("invalid nf_call_ip6tables", *argv); addattr8(n, 1024, IFLA_BR_NF_CALL_IP6TABLES, nf_call_ip6t); } else if (matches(*argv, "nf_call_arptables") == 0) { __u8 nf_call_arpt; NEXT_ARG(); if (get_u8(&nf_call_arpt, *argv, 0)) invarg("invalid nf_call_arptables", *argv); addattr8(n, 1024, IFLA_BR_NF_CALL_ARPTABLES, nf_call_arpt); } else if (matches(*argv, "help") == 0) { explain(); return -1; } else { fprintf(stderr, "bridge: unknown command \"%s\"?\n", *argv); explain(); return -1; } argc--, argv++; } return 0; }
static int parse_csum(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { struct tc_csum sel; int argc = *argc_p; char **argv = *argv_p; int ok = 0; struct rtattr *tail; memset(&sel, 0, sizeof(sel)); while (argc > 0) { if (matches(*argv, "csum") == 0) { NEXT_ARG(); if (parse_csum_args(&argc, &argv, &sel)) { fprintf(stderr, "Illegal csum construct (%s)\n", *argv); explain(); return -1; } ok++; continue; } else if (matches(*argv, "help") == 0) { usage(); } else { break; } } if (!ok) { explain(); return -1; } if (sel.update_flags == 0) { fprintf(stderr, "Illegal csum construct, empty <UPDATE> list\n"); return -1; } if (argc) { if (matches(*argv, "reclassify") == 0) { sel.action = TC_ACT_RECLASSIFY; argc--; argv++; } else if (matches(*argv, "pipe") == 0) { sel.action = TC_ACT_PIPE; argc--; argv++; } else if (matches(*argv, "drop") == 0 || matches(*argv, "shot") == 0) { sel.action = TC_ACT_SHOT; argc--; argv++; } else if (matches(*argv, "continue") == 0) { sel.action = TC_ACT_UNSPEC; argc--; argv++; } else if (matches(*argv, "pass") == 0) { sel.action = TC_ACT_OK; argc--; argv++; } } if (argc) { if (matches(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&sel.index, *argv, 10)) { fprintf(stderr, "Illegal \"index\" (%s) <csum>\n", *argv); return -1; } argc--; argv++; } } tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, tca_id, NULL, 0); addattr_l(n, MAX_MSG, TCA_CSUM_PARMS, &sel, sizeof(sel)); tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; *argc_p = argc; *argv_p = argv; return 0; }
int netlink_link_add_vmac(vrrp_rt *vrrp) { struct rtattr *linkinfo; interface *ifp; char ifname[IFNAMSIZ]; struct { struct nlmsghdr n; struct ifinfomsg ifi; char buf[256]; } req; if (!vrrp->ifp) return -1; memset(&req, 0, sizeof (req)); memset(ifname, 0, IFNAMSIZ); strncpy(ifname, vrrp->vmac_ifname, IFNAMSIZ - 1); /* * Check to see if this vmac interface was created * by a previous instance. */ if (reload && (ifp = if_get_by_ifname(ifname))) { vrrp->xmit_ifp = ifp; /* Save ifindex for use on delete */ vrrp->vmac_ifindex = IF_INDEX(vrrp->xmit_ifp); vrrp->vmac |= 2; return 1; } req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; req.n.nlmsg_type = RTM_NEWLINK; req.ifi.ifi_family = AF_INET; /* macvlan settings */ linkinfo = NLMSG_TAIL(&req.n); addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, (void *)ll_kind, strlen(ll_kind)); linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; addattr_l(&req.n, sizeof(req), IFLA_LINK, &IF_INDEX(vrrp->ifp), sizeof(uint32_t)); addattr_l(&req.n, sizeof(req), IFLA_IFNAME, ifname, strlen(ifname)); if (netlink_talk(&nl_cmd, &req.n) < 0) return -1; /* * Update interface queue and vrrp instance interface binding. * bring it UP ! */ netlink_interface_lookup(); ifp = if_get_by_ifname(ifname); if (!ifp) return -1; vrrp->xmit_ifp = ifp; vrrp->vmac_ifindex = IF_INDEX(vrrp->xmit_ifp); /* For use on delete */ vrrp->vmac |= 2; netlink_link_setlladdr(vrrp); vyatta_if_setup(ifname); netlink_link_up(vrrp); netlink_link_setmode(vrrp); return 1; }
static int parse_ipt(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { struct xtables_target *m = NULL; struct ipt_entry fw; struct rtattr *tail; int c; int rargc = *argc_p; char **argv = *argv_p; int argc = 0, iargc = 0; char k[FILTER_NAMESZ]; int size = 0; int iok = 0, ok = 0; __u32 hook = 0, index = 0; set_lib_dir(); { int i; for (i = 0; i < rargc; i++) { if (NULL == argv[i] || 0 == strcmp(argv[i], "action")) { break; } } iargc = argc = i; } if (argc <= 2) { fprintf(stderr, "bad arguments to ipt %d vs %d\n", argc, rargc); return -1; } while (1) { c = getopt_long(argc, argv, "j:", opts, NULL); if (c == -1) break; switch (c) { case 'j': m = find_target(optarg, TRY_LOAD); if (m != NULL) { if (build_st(m, NULL) < 0) { printf(" %s error\n", m->name); return -1; } opts = merge_options(opts, m->extra_opts, &m->option_offset); } else { fprintf(stderr, " failed to find target %s\n\n", optarg); return -1; } ok++; break; default: memset(&fw, 0, sizeof(fw)); if (m) { m->parse(c - m->option_offset, argv, 0, &m->tflags, NULL, &m->t); } else { fprintf(stderr, " failed to find target %s\n\n", optarg); return -1; } ok++; break; } } if (iargc > optind) { if (matches(argv[optind], "index") == 0) { if (get_u32(&index, argv[optind + 1], 10)) { fprintf(stderr, "Illegal \"index\"\n"); free_opts(opts); return -1; } iok++; optind += 2; } } if (!ok && !iok) { fprintf(stderr, " ipt Parser BAD!! (%s)\n", *argv); return -1; } /* check that we passed the correct parameters to the target */ if (m) m->final_check(m->tflags); { struct tcmsg *t = NLMSG_DATA(n); if (t->tcm_parent != TC_H_ROOT && t->tcm_parent == TC_H_MAJ(TC_H_INGRESS)) { hook = NF_IP_PRE_ROUTING; } else { hook = NF_IP_POST_ROUTING; } } tail = addattr_nest(n, MAX_MSG, tca_id); fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]); fprintf(stdout, "\ttarget: "); if (m) m->print(NULL, m->t, 0); fprintf(stdout, " index %d\n", index); if (strlen(tname) > 16) { size = 16; k[15] = 0; } else { size = 1 + strlen(tname); } strncpy(k, tname, size); addattr_l(n, MAX_MSG, TCA_IPT_TABLE, k, size); addattr_l(n, MAX_MSG, TCA_IPT_HOOK, &hook, 4); addattr_l(n, MAX_MSG, TCA_IPT_INDEX, &index, 4); if (m) addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size); addattr_nest_end(n, tail); argc -= optind; argv += optind; *argc_p = rargc - iargc; *argv_p = argv; optind = 0; free_opts(opts); /* Clear flags if target will be used again */ m->tflags = 0; m->used = 0; /* Free allocated memory */ if (m->t) free(m->t); 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 gre_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { struct { struct nlmsghdr n; struct ifinfomsg i; char buf[1024]; } req; struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *greinfo[IFLA_GRE_MAX + 1]; __u16 iflags = 0; __u16 oflags = 0; unsigned ikey = 0; unsigned okey = 0; struct in6_addr raddr = IN6ADDR_ANY_INIT; struct in6_addr laddr = IN6ADDR_ANY_INIT; unsigned link = 0; unsigned flowinfo = 0; unsigned flags = 0; __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT; __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT; int len; if (!(n->nlmsg_flags & NLM_F_CREATE)) { memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETLINK; req.i.ifi_family = preferred_family; req.i.ifi_index = ifi->ifi_index; if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) { get_failed: fprintf(stderr, "Failed to get existing tunnel info.\n"); return -1; } len = req.n.nlmsg_len; len -= NLMSG_LENGTH(sizeof(*ifi)); if (len < 0) goto get_failed; parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len); if (!tb[IFLA_LINKINFO]) goto get_failed; parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); if (!linkinfo[IFLA_INFO_DATA]) goto get_failed; parse_rtattr_nested(greinfo, IFLA_GRE_MAX, linkinfo[IFLA_INFO_DATA]); if (greinfo[IFLA_GRE_IKEY]) ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]); if (greinfo[IFLA_GRE_OKEY]) okey = rta_getattr_u32(greinfo[IFLA_GRE_OKEY]); if (greinfo[IFLA_GRE_IFLAGS]) iflags = rta_getattr_u16(greinfo[IFLA_GRE_IFLAGS]); if (greinfo[IFLA_GRE_OFLAGS]) oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]); if (greinfo[IFLA_GRE_LOCAL]) memcpy(&laddr, RTA_DATA(greinfo[IFLA_GRE_LOCAL]), sizeof(laddr)); if (greinfo[IFLA_GRE_REMOTE]) memcpy(&raddr, RTA_DATA(greinfo[IFLA_GRE_REMOTE]), sizeof(raddr)); if (greinfo[IFLA_GRE_TTL]) hop_limit = rta_getattr_u8(greinfo[IFLA_GRE_TTL]); if (greinfo[IFLA_GRE_LINK]) link = rta_getattr_u32(greinfo[IFLA_GRE_LINK]); if (greinfo[IFLA_GRE_ENCAP_LIMIT]) encap_limit = rta_getattr_u8(greinfo[IFLA_GRE_ENCAP_LIMIT]); if (greinfo[IFLA_GRE_FLOWINFO]) flowinfo = rta_getattr_u32(greinfo[IFLA_GRE_FLOWINFO]); if (greinfo[IFLA_GRE_FLAGS]) flags = rta_getattr_u32(greinfo[IFLA_GRE_FLAGS]); } while (argc > 0) { if (!matches(*argv, "key")) { unsigned uval; NEXT_ARG(); iflags |= GRE_KEY; oflags |= GRE_KEY; if (strchr(*argv, '.')) uval = get_addr32(*argv); else { if (get_unsigned(&uval, *argv, 0) < 0) { fprintf(stderr, "Invalid value for \"key\"\n"); exit(-1); } uval = htonl(uval); } ikey = okey = uval; } else if (!matches(*argv, "ikey")) { unsigned uval; NEXT_ARG(); iflags |= GRE_KEY; if (strchr(*argv, '.')) uval = get_addr32(*argv); else { if (get_unsigned(&uval, *argv, 0)<0) { fprintf(stderr, "invalid value of \"ikey\"\n"); exit(-1); } uval = htonl(uval); } ikey = uval; } else if (!matches(*argv, "okey")) { unsigned uval; NEXT_ARG(); oflags |= GRE_KEY; if (strchr(*argv, '.')) uval = get_addr32(*argv); else { if (get_unsigned(&uval, *argv, 0)<0) { fprintf(stderr, "invalid value of \"okey\"\n"); exit(-1); } uval = htonl(uval); } okey = uval; } else if (!matches(*argv, "seq")) { iflags |= GRE_SEQ; oflags |= GRE_SEQ; } else if (!matches(*argv, "iseq")) { iflags |= GRE_SEQ; } else if (!matches(*argv, "oseq")) { oflags |= GRE_SEQ; } else if (!matches(*argv, "csum")) { iflags |= GRE_CSUM; oflags |= GRE_CSUM; } else if (!matches(*argv, "icsum")) { iflags |= GRE_CSUM; } else if (!matches(*argv, "ocsum")) { oflags |= GRE_CSUM; } else if (!matches(*argv, "remote")) { inet_prefix addr; NEXT_ARG(); get_prefix(&addr, *argv, preferred_family); if (addr.family == AF_UNSPEC) invarg("\"remote\" address family is AF_UNSPEC", *argv); memcpy(&raddr, &addr.data, sizeof(raddr)); } else if (!matches(*argv, "local")) { inet_prefix addr; NEXT_ARG(); get_prefix(&addr, *argv, preferred_family); if (addr.family == AF_UNSPEC) invarg("\"local\" address family is AF_UNSPEC", *argv); memcpy(&laddr, &addr.data, sizeof(laddr)); } else if (!matches(*argv, "dev")) { NEXT_ARG(); link = if_nametoindex(*argv); if (link == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", *argv); exit(-1); } } else if (!matches(*argv, "ttl") || !matches(*argv, "hoplimit")) { __u8 uval; NEXT_ARG(); if (get_u8(&uval, *argv, 0)) invarg("invalid TTL", *argv); hop_limit = uval; } else if (!matches(*argv, "tos") || !matches(*argv, "tclass") || !matches(*argv, "dsfield")) { __u8 uval; NEXT_ARG(); if (strcmp(*argv, "inherit") == 0) flags |= IP6_TNL_F_USE_ORIG_TCLASS; else { if (get_u8(&uval, *argv, 16)) invarg("invalid TClass", *argv); flowinfo |= htonl((__u32)uval << 20) & IP6_FLOWINFO_TCLASS; flags &= ~IP6_TNL_F_USE_ORIG_TCLASS; } } else if (strcmp(*argv, "flowlabel") == 0 || strcmp(*argv, "fl") == 0) { __u32 uval; NEXT_ARG(); if (strcmp(*argv, "inherit") == 0) flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL; else { if (get_u32(&uval, *argv, 16)) invarg("invalid Flowlabel", *argv); if (uval > 0xFFFFF) invarg("invalid Flowlabel", *argv); flowinfo |= htonl(uval) & IP6_FLOWINFO_FLOWLABEL; flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL; } } else if (strcmp(*argv, "dscp") == 0) { NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) invarg("not inherit", *argv); flags |= IP6_TNL_F_RCV_DSCP_COPY; } else usage(); argc--; argv++; } addattr32(n, 1024, IFLA_GRE_IKEY, ikey); addattr32(n, 1024, IFLA_GRE_OKEY, okey); addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2); addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2); addattr_l(n, 1024, IFLA_GRE_LOCAL, &laddr, sizeof(laddr)); addattr_l(n, 1024, IFLA_GRE_REMOTE, &raddr, sizeof(raddr)); if (link) addattr32(n, 1024, IFLA_GRE_LINK, link); addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1); addattr_l(n, 1024, IFLA_GRE_ENCAP_LIMIT, &encap_limit, 1); addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4); addattr_l(n, 1024, IFLA_GRE_FLAGS, &flowinfo, 4); return 0; }
static int fq_pie_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { unsigned limit = 0; unsigned flows = 0; unsigned target = 0; unsigned quantum = 0; unsigned tupdate = 0; unsigned alpha = 0; unsigned beta = 0; int ecn = -1; int bytemode = -1; struct rtattr *tail; while (argc > 0) { if (strcmp(*argv, "limit") == 0) { NEXT_ARG(); if (get_unsigned(&limit, *argv, 0)) { fprintf(stderr, "Illegal \"limit\"\n"); return -1; } } else if (strcmp(*argv, "flows") == 0) { NEXT_ARG(); if (get_unsigned(&flows, *argv, 0)) { fprintf(stderr, "Illegal \"flows\"\n"); return -1; } } else if (strcmp(*argv, "quantum") == 0) { NEXT_ARG(); if (get_unsigned(&quantum, *argv, 0)) { fprintf(stderr, "Illegal \"quantum\"\n"); return -1; } } else if (strcmp(*argv, "target") == 0) { NEXT_ARG(); if (get_time(&target, *argv)) { fprintf(stderr, "Illegal \"target\"\n"); return -1; } } else if (strcmp(*argv, "tupdate") == 0) { NEXT_ARG(); if (get_time(&tupdate, *argv)) { fprintf(stderr, "Illegal \"tupdate\"\n"); return -1; } } else if (strcmp(*argv, "alpha") == 0) { NEXT_ARG(); if (get_unsigned(&alpha, *argv, 0) || (alpha > ALPHA_MAX) || (alpha < ALPHA_MIN)) { fprintf(stderr, "Illegal \"alpha\"\n"); return -1; } } else if (strcmp(*argv, "beta") == 0) { NEXT_ARG(); if (get_unsigned(&beta, *argv, 0) || (beta > BETA_MAX) || (beta < BETA_MIN)) { fprintf(stderr, "Illegal \"beta\"\n"); return -1; } } else if (strcmp(*argv, "ecn") == 0) { ecn = 1; } else if (strcmp(*argv, "noecn") == 0) { ecn = 0; } else if (strcmp(*argv, "bytemode") == 0) { bytemode = 1; } else if (strcmp(*argv, "nobytemode") == 0) { bytemode = 0; } else if (strcmp(*argv, "help") == 0) { explain(); return -1; } else { fprintf(stderr, "What is \"%s\"?\n", *argv); explain(); return -1; } argc--; argv++; } tail = NLMSG_TAIL(n); addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); if (limit) addattr_l(n, 1024, TCA_FQ_PIE_LIMIT, &limit, sizeof(limit)); if (flows) addattr_l(n, 1024, TCA_FQ_PIE_FLOWS, &flows, sizeof(flows)); if (quantum) addattr_l(n, 1024, TCA_FQ_PIE_QUANTUM, &quantum, sizeof(quantum)); if (tupdate) addattr_l(n, 1024, TCA_FQ_PIE_TUPDATE, &tupdate, sizeof(tupdate)); if (target) addattr_l(n, 1024, TCA_FQ_PIE_TARGET, &target, sizeof(target)); if (alpha) addattr_l(n, 1024, TCA_FQ_PIE_ALPHA, &alpha, sizeof(alpha)); if (beta) addattr_l(n, 1024, TCA_FQ_PIE_BETA, &beta, sizeof(beta)); if (ecn != -1) addattr_l(n, 1024, TCA_FQ_PIE_ECN, &ecn, sizeof(ecn)); if (bytemode != -1) addattr_l(n, 1024, TCA_FQ_PIE_BYTEMODE, &bytemode, sizeof(bytemode)); tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; return 0; }