static int xfrm_state_extra_flag_parse(__u32 *extra_flags, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; int len = strlen(*argv); if (len > 2 && strncmp(*argv, "0x", 2) == 0) { __u32 val = 0; if (get_u32(&val, *argv, 16)) invarg("\"EXTRA-FLAG\" is invalid", *argv); *extra_flags = val; } else { while (1) { if (strcmp(*argv, "dont-encap-dscp") == 0) *extra_flags |= XFRM_SA_XFLAG_DONT_ENCAP_DSCP; else { PREV_ARG(); /* back track */ break; } if (!NEXT_ARG_OK()) break; NEXT_ARG(); } } *argcp = argc; *argvp = argv; return 0; }
static int xfrm_policy_flag_parse(__u8 *flags, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; int len = strlen(*argv); if (len > 2 && strncmp(*argv, "0x", 2) == 0) { __u8 val = 0; if (get_u8(&val, *argv, 16)) invarg("\"FLAG\" is invalid", *argv); *flags = val; } else { while (1) { if (strcmp(*argv, "localok") == 0) *flags |= XFRM_POLICY_LOCALOK; else { PREV_ARG(); /* back track */ break; } if (!NEXT_ARG_OK()) break; NEXT_ARG(); } } *argcp = argc; *argvp = argv; return 0; }
int xfrm_parse_mark(struct xfrm_mark *mark, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; NEXT_ARG(); if (get_u32(&mark->v, *argv, 0)) { invarg("Illegal \"mark\" value\n", *argv); } if (argc > 1) NEXT_ARG(); else { /* last entry on parse line */ mark->m = 0xffffffff; goto done; } if (strcmp(*argv, "mask") == 0) { NEXT_ARG(); if (get_u32(&mark->m, *argv, 0)) { invarg("Illegal \"mark\" mask\n", *argv); } } else { mark->m = 0xffffffff; PREV_ARG(); } done: *argcp = argc; *argvp = argv; return 0; }
static int xfrm_tmpl_parse(struct xfrm_user_tmpl *tmpl, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; char *idp = NULL; while (1) { if (strcmp(*argv, "mode") == 0) { NEXT_ARG(); xfrm_mode_parse(&tmpl->mode, &argc, &argv); } else if (strcmp(*argv, "reqid") == 0) { NEXT_ARG(); xfrm_reqid_parse(&tmpl->reqid, &argc, &argv); } else if (strcmp(*argv, "level") == 0) { NEXT_ARG(); if (strcmp(*argv, "required") == 0) tmpl->optional = 0; else if (strcmp(*argv, "use") == 0) tmpl->optional = 1; else invarg("\"LEVEL\" is invalid\n", *argv); } else { if (idp) { PREV_ARG(); /* back track */ break; } idp = *argv; xfrm_id_parse(&tmpl->saddr, &tmpl->id, &tmpl->family, 0, &argc, &argv); if (preferred_family == AF_UNSPEC) preferred_family = tmpl->family; } if (!NEXT_ARG_OK()) break; NEXT_ARG(); } if (argc == *argcp) missarg("TMPL"); *argcp = argc; *argvp = argv; return 0; }
static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; int len = strlen(*argv); if (len > 2 && strncmp(*argv, "0x", 2) == 0) { __u8 val = 0; if (get_u8(&val, *argv, 16)) invarg("FLAG value is invalid", *argv); *flags = val; } else { while (1) { if (strcmp(*argv, "noecn") == 0) *flags |= XFRM_STATE_NOECN; else if (strcmp(*argv, "decap-dscp") == 0) *flags |= XFRM_STATE_DECAP_DSCP; else if (strcmp(*argv, "nopmtudisc") == 0) *flags |= XFRM_STATE_NOPMTUDISC; else if (strcmp(*argv, "wildrecv") == 0) *flags |= XFRM_STATE_WILDRECV; else if (strcmp(*argv, "icmp") == 0) *flags |= XFRM_STATE_ICMP; else if (strcmp(*argv, "af-unspec") == 0) *flags |= XFRM_STATE_AF_UNSPEC; else if (strcmp(*argv, "align4") == 0) *flags |= XFRM_STATE_ALIGN4; else if (strcmp(*argv, "esn") == 0) *flags |= XFRM_STATE_ESN; else { PREV_ARG(); /* back track */ break; } if (!NEXT_ARG_OK()) break; NEXT_ARG(); } } *argcp = argc; *argvp = argv; return 0; }
static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; int len = strlen(*argv); if (len > 2 && strncmp(*argv, "0x", 2) == 0) { __u8 val = 0; if (get_u8(&val, *argv, 16)) invarg("\"FLAG\" is invalid", *argv); *flags = val; } else { while (1) { if (strcmp(*argv, "noecn") == 0) *flags |= XFRM_STATE_NOECN; else if (strcmp(*argv, "decap-dscp") == 0) *flags |= XFRM_STATE_DECAP_DSCP; else if (strcmp(*argv, "wildrecv") == 0) *flags |= XFRM_STATE_WILDRECV; else { PREV_ARG(); /* back track */ break; } if (!NEXT_ARG_OK()) break; NEXT_ARG(); } } filter.state_flags_mask = XFRM_FILTER_MASK_FULL; *argcp = argc; *argvp = argv; return 0; }
int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family, int loose, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; inet_prefix dst; inet_prefix src; memset(&dst, 0, sizeof(dst)); memset(&src, 0, sizeof(src)); while (1) { if (strcmp(*argv, "src") == 0) { NEXT_ARG(); get_prefix(&src, *argv, preferred_family); if (src.family == AF_UNSPEC) invarg("\"src\" address family is AF_UNSPEC", *argv); if (family) *family = src.family; memcpy(saddr, &src.data, sizeof(*saddr)); filter.id_src_mask = src.bitlen; } else if (strcmp(*argv, "dst") == 0) { NEXT_ARG(); get_prefix(&dst, *argv, preferred_family); if (dst.family == AF_UNSPEC) invarg("\"dst\" address family is AF_UNSPEC", *argv); if (family) *family = dst.family; memcpy(&id->daddr, &dst.data, sizeof(id->daddr)); filter.id_dst_mask = dst.bitlen; } else if (strcmp(*argv, "proto") == 0) { int ret; NEXT_ARG(); ret = xfrm_xfrmproto_getbyname(*argv); if (ret < 0) invarg("\"XFRM_PROTO\" is invalid", *argv); id->proto = (__u8)ret; filter.id_proto_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "spi") == 0) { __u32 spi; NEXT_ARG(); if (get_u32(&spi, *argv, 0)) invarg("\"SPI\" is invalid", *argv); spi = htonl(spi); id->spi = spi; filter.id_spi_mask = XFRM_FILTER_MASK_FULL; } else { PREV_ARG(); /* back track */ break; } if (!NEXT_ARG_OK()) break; NEXT_ARG(); } if (src.family && dst.family && (src.family != dst.family)) invarg("the same address family is required between \"src\" and \"dst\"", *argv); if (loose == 0 && id->proto == 0) missarg("XFRM_PROTO"); if (argc == *argcp) missarg("ID"); *argcp = argc; *argvp = argv; return 0; }
int xfrm_selector_parse(struct xfrm_selector *sel, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; inet_prefix dst; inet_prefix src; char *upspecp = NULL; memset(&dst, 0, sizeof(dst)); memset(&src, 0, sizeof(src)); while (1) { if (strcmp(*argv, "src") == 0) { NEXT_ARG(); get_prefix(&src, *argv, preferred_family); if (src.family == AF_UNSPEC) invarg("\"src\" address family is AF_UNSPEC", *argv); sel->family = src.family; memcpy(&sel->saddr, &src.data, sizeof(sel->saddr)); sel->prefixlen_s = src.bitlen; filter.sel_src_mask = src.bitlen; } else if (strcmp(*argv, "dst") == 0) { NEXT_ARG(); get_prefix(&dst, *argv, preferred_family); if (dst.family == AF_UNSPEC) invarg("\"dst\" address family is AF_UNSPEC", *argv); sel->family = dst.family; memcpy(&sel->daddr, &dst.data, sizeof(sel->daddr)); sel->prefixlen_d = dst.bitlen; filter.sel_dst_mask = dst.bitlen; } else if (strcmp(*argv, "dev") == 0) { int ifindex; NEXT_ARG(); if (strcmp(*argv, "none") == 0) ifindex = 0; else { ifindex = ll_name_to_index(*argv); if (ifindex <= 0) invarg("\"DEV\" is invalid", *argv); } sel->ifindex = ifindex; filter.sel_dev_mask = XFRM_FILTER_MASK_FULL; } else { if (upspecp) { PREV_ARG(); /* back track */ break; } else { upspecp = *argv; xfrm_selector_upspec_parse(sel, &argc, &argv); } } if (!NEXT_ARG_OK()) break; NEXT_ARG(); } if (src.family && dst.family && (src.family != dst.family)) invarg("the same address family is required between \"src\" and \"dst\"", *argv); if (argc == *argcp) missarg("SELECTOR"); *argcp = argc; *argvp = argv; return 0; }
static int xfrm_selector_upspec_parse(struct xfrm_selector *sel, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; char *sportp = NULL; char *dportp = NULL; char *typep = NULL; char *codep = NULL; while (1) { if (strcmp(*argv, "proto") == 0) { __u8 upspec; NEXT_ARG(); if (strcmp(*argv, "any") == 0) upspec = 0; else { struct protoent *pp; pp = getprotobyname(*argv); if (pp) upspec = pp->p_proto; else { if (get_u8(&upspec, *argv, 0)) invarg("\"PROTO\" is invalid", *argv); } } sel->proto = upspec; filter.upspec_proto_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "sport") == 0) { sportp = *argv; NEXT_ARG(); if (get_u16(&sel->sport, *argv, 0)) invarg("\"PORT\" is invalid", *argv); sel->sport = htons(sel->sport); if (sel->sport) sel->sport_mask = ~((__u16)0); filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "dport") == 0) { dportp = *argv; NEXT_ARG(); if (get_u16(&sel->dport, *argv, 0)) invarg("\"PORT\" is invalid", *argv); sel->dport = htons(sel->dport); if (sel->dport) sel->dport_mask = ~((__u16)0); filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "type") == 0) { typep = *argv; NEXT_ARG(); if (get_u16(&sel->sport, *argv, 0) || (sel->sport & ~((__u16)0xff))) invarg("\"type\" value is invalid", *argv); sel->sport = htons(sel->sport); sel->sport_mask = ~((__u16)0); filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "code") == 0) { codep = *argv; NEXT_ARG(); if (get_u16(&sel->dport, *argv, 0) || (sel->dport & ~((__u16)0xff))) invarg("\"code\" value is invalid", *argv); sel->dport = htons(sel->dport); sel->dport_mask = ~((__u16)0); filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL; } else { PREV_ARG(); /* back track */ break; } if (!NEXT_ARG_OK()) break; NEXT_ARG(); } if (argc == *argcp) missarg("UPSPEC"); if (sportp || dportp) { switch (sel->proto) { case IPPROTO_TCP: case IPPROTO_UDP: case IPPROTO_SCTP: case IPPROTO_DCCP: break; default: fprintf(stderr, "\"sport\" and \"dport\" are invalid with proto=%s\n", strxf_proto(sel->proto)); exit(1); } } if (typep || codep) { switch (sel->proto) { case IPPROTO_ICMP: case IPPROTO_ICMPV6: case IPPROTO_MH: break; default: fprintf(stderr, "\"type\" and \"code\" are invalid with proto=%s\n", strxf_proto(sel->proto)); exit(1); } } *argcp = argc; *argvp = argv; return 0; }
int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family, int loose, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; inet_prefix dst; inet_prefix src; memset(&dst, 0, sizeof(dst)); memset(&src, 0, sizeof(src)); while (1) { if (strcmp(*argv, "src") == 0) { NEXT_ARG(); get_prefix(&src, *argv, preferred_family); if (src.family == AF_UNSPEC) invarg("value after \"src\" has an unrecognized address family", *argv); if (family) *family = src.family; memcpy(saddr, &src.data, sizeof(*saddr)); filter.id_src_mask = src.bitlen; } else if (strcmp(*argv, "dst") == 0) { NEXT_ARG(); get_prefix(&dst, *argv, preferred_family); if (dst.family == AF_UNSPEC) invarg("value after \"dst\" has an unrecognized address family", *argv); if (family) *family = dst.family; memcpy(&id->daddr, &dst.data, sizeof(id->daddr)); filter.id_dst_mask = dst.bitlen; } else if (strcmp(*argv, "proto") == 0) { int ret; NEXT_ARG(); ret = xfrm_xfrmproto_getbyname(*argv); if (ret < 0) invarg("XFRM-PROTO value is invalid", *argv); id->proto = (__u8)ret; filter.id_proto_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "spi") == 0) { __u32 spi; NEXT_ARG(); if (get_u32(&spi, *argv, 0)) invarg("SPI value is invalid", *argv); spi = htonl(spi); id->spi = spi; filter.id_spi_mask = XFRM_FILTER_MASK_FULL; } else { PREV_ARG(); /* back track */ break; } if (!NEXT_ARG_OK()) break; NEXT_ARG(); } if (src.family && dst.family && (src.family != dst.family)) invarg("the same address family is required between values after \"src\" and \"dst\"", *argv); if (id->spi && id->proto) { if (xfrm_xfrmproto_is_ro(id->proto)) { fprintf(stderr, "\"spi\" is invalid with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(id->proto)); exit(1); } else if (id->proto == IPPROTO_COMP && ntohl(id->spi) >= 0x10000) { fprintf(stderr, "SPI value is too large with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(id->proto)); exit(1); } } if (loose == 0 && id->proto == 0) missarg("XFRM-PROTO"); if (argc == *argcp) missarg("ID"); *argcp = argc; *argvp = argv; return 0; }
static int iplink_parse_vf(int vf, int *argcp, char ***argvp, struct iplink_req *req, int dev_index) { char new_rate_api = 0, count = 0, override_legacy_rate = 0; struct ifla_vf_rate tivt; int len, argc = *argcp; char **argv = *argvp; struct rtattr *vfinfo; tivt.min_tx_rate = -1; tivt.max_tx_rate = -1; vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO); while (NEXT_ARG_OK()) { NEXT_ARG(); count++; if (!matches(*argv, "max_tx_rate")) { /* new API in use */ new_rate_api = 1; /* override legacy rate */ override_legacy_rate = 1; } else if (!matches(*argv, "min_tx_rate")) { /* new API in use */ new_rate_api = 1; } } while (count--) { /* rewind arg */ PREV_ARG(); } while (NEXT_ARG_OK()) { NEXT_ARG(); if (matches(*argv, "mac") == 0) { struct ifla_vf_mac ivm; NEXT_ARG(); ivm.vf = vf; len = ll_addr_a2n((char *)ivm.mac, 32, *argv); if (len < 0) return -1; addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm)); } else if (matches(*argv, "vlan") == 0) { struct ifla_vf_vlan ivv; NEXT_ARG(); if (get_unsigned(&ivv.vlan, *argv, 0)) { invarg("Invalid \"vlan\" value\n", *argv); } ivv.vf = vf; ivv.qos = 0; if (NEXT_ARG_OK()) { NEXT_ARG(); if (matches(*argv, "qos") == 0) { NEXT_ARG(); if (get_unsigned(&ivv.qos, *argv, 0)) { invarg("Invalid \"qos\" value\n", *argv); } } else { /* rewind arg */ PREV_ARG(); } } addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, &ivv, sizeof(ivv)); } else if (matches(*argv, "rate") == 0) { struct ifla_vf_tx_rate ivt; NEXT_ARG(); if (get_unsigned(&ivt.rate, *argv, 0)) { invarg("Invalid \"rate\" value\n", *argv); } ivt.vf = vf; if (!new_rate_api) addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE, &ivt, sizeof(ivt)); else if (!override_legacy_rate) tivt.max_tx_rate = ivt.rate; } else if (matches(*argv, "max_tx_rate") == 0) { NEXT_ARG(); if (get_unsigned(&tivt.max_tx_rate, *argv, 0)) invarg("Invalid \"max tx rate\" value\n", *argv); tivt.vf = vf; } else if (matches(*argv, "min_tx_rate") == 0) { NEXT_ARG(); if (get_unsigned(&tivt.min_tx_rate, *argv, 0)) invarg("Invalid \"min tx rate\" value\n", *argv); tivt.vf = vf; } else if (matches(*argv, "spoofchk") == 0) { struct ifla_vf_spoofchk ivs; NEXT_ARG(); if (matches(*argv, "on") == 0) ivs.setting = 1; else if (matches(*argv, "off") == 0) ivs.setting = 0; else invarg("Invalid \"spoofchk\" value\n", *argv); ivs.vf = vf; addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs)); } else if (matches(*argv, "state") == 0) { struct ifla_vf_link_state ivl; NEXT_ARG(); if (matches(*argv, "auto") == 0) ivl.link_state = IFLA_VF_LINK_STATE_AUTO; else if (matches(*argv, "enable") == 0) ivl.link_state = IFLA_VF_LINK_STATE_ENABLE; else if (matches(*argv, "disable") == 0) ivl.link_state = IFLA_VF_LINK_STATE_DISABLE; else invarg("Invalid \"state\" value\n", *argv); ivl.vf = vf; addattr_l(&req->n, sizeof(*req), IFLA_VF_LINK_STATE, &ivl, sizeof(ivl)); } else { /* rewind arg */ PREV_ARG(); break; } } if (new_rate_api) { int tmin, tmax; if (tivt.min_tx_rate == -1 || tivt.max_tx_rate == -1) { ipaddr_get_vf_rate(tivt.vf, &tmin, &tmax, dev_index); if (tivt.min_tx_rate == -1) tivt.min_tx_rate = tmin; if (tivt.max_tx_rate == -1) tivt.max_tx_rate = tmax; } addattr_l(&req->n, sizeof(*req), IFLA_VF_RATE, &tivt, sizeof(tivt)); } if (argc == *argcp) incomplete_command(); addattr_nest_end(&req->n, vfinfo); *argcp = argc; *argvp = argv; return 0; }
static int iplink_parse_vf(int vf, int *argcp, char ***argvp, struct iplink_req *req) { int len, argc = *argcp; char **argv = *argvp; struct rtattr *vfinfo; vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO); while (NEXT_ARG_OK()) { NEXT_ARG(); if (matches(*argv, "mac") == 0) { struct ifla_vf_mac ivm; NEXT_ARG(); ivm.vf = vf; len = ll_addr_a2n((char *)ivm.mac, 32, *argv); if (len < 0) return -1; addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm)); } else if (matches(*argv, "vlan") == 0) { struct ifla_vf_vlan ivv; NEXT_ARG(); if (get_unsigned(&ivv.vlan, *argv, 0)) { invarg("Invalid \"vlan\" value\n", *argv); } ivv.vf = vf; ivv.qos = 0; if (NEXT_ARG_OK()) { NEXT_ARG(); if (matches(*argv, "qos") == 0) { NEXT_ARG(); if (get_unsigned(&ivv.qos, *argv, 0)) { invarg("Invalid \"qos\" value\n", *argv); } } else { /* rewind arg */ PREV_ARG(); } } addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, &ivv, sizeof(ivv)); } else if (matches(*argv, "rate") == 0) { struct ifla_vf_tx_rate ivt; NEXT_ARG(); if (get_unsigned(&ivt.rate, *argv, 0)) { invarg("Invalid \"rate\" value\n", *argv); } ivt.vf = vf; addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE, &ivt, sizeof(ivt)); } else if (matches(*argv, "spoofchk") == 0) { struct ifla_vf_spoofchk ivs; NEXT_ARG(); if (matches(*argv, "on") == 0) ivs.setting = 1; else if (matches(*argv, "off") == 0) ivs.setting = 0; else invarg("Invalid \"spoofchk\" value\n", *argv); ivs.vf = vf; addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs)); } else { /* rewind arg */ PREV_ARG(); break; } } if (argc == *argcp) incomplete_command(); addattr_nest_end(&req->n, vfinfo); *argcp = argc; *argvp = argv; return 0; }
void mpls_parse_instr(struct mpls_instr_req *instr, int *pargc, char ***pargv, int direction) { int argc = *pargc; char **argv = *pargv; int c = 0; while (argc > 0) { if (strcmp(*argv, "nexthop") == 0) { NEXT_ARG(); inet_prefix addr; instr->mir_instr[c].mir_opcode = MPLS_OP_SET; instr->mir_instr[c].mir_set.mni_if = ll_name_to_index(*argv); NEXT_ARG(); if (strcmp(*argv, "ipv4") == 0) { struct sockaddr_in *sin = (struct sockaddr_in*) &instr->mir_instr[c].mir_set.mni_addr; NEXT_ARG(); get_addr(&addr, *argv, AF_INET); sin->sin_family = AF_INET; memcpy(&sin->sin_addr, &addr.data, addr.bytelen); } else if (strcmp(*argv, "ipv6") == 0) { struct sockaddr_in6 *sin6=(struct sockaddr_in6*) &instr->mir_instr[c].mir_set.mni_addr; NEXT_ARG(); get_addr(&addr, *argv, AF_INET6); sin6->sin6_family = AF_INET6; memcpy(&sin6->sin6_addr, &addr.data, addr.bytelen); } else if (strcmp(*argv, "packet") == 0) { struct sockaddr *s = &instr->mir_instr[c].mir_set.mni_addr; s->sa_family = AF_PACKET; } else if (strcmp(*argv, "none") == 0) { struct sockaddr *s = &instr->mir_instr[c].mir_set.mni_addr; memset(s, 0, sizeof(struct sockaddr)); continue; } else { invarg(*argv, "invalid nexthop type"); } } else if (strcmp(*argv, "push") == 0) { NEXT_ARG(); instr->mir_instr[c].mir_opcode = MPLS_OP_PUSH; *pargc = argc; *pargv = argv; mpls_parse_label(&instr->mir_instr[c].mir_push, pargc, pargv); argc = *pargc; argv = *pargv; } else if (strcmp(*argv, "forward") == 0) { __u32 key; NEXT_ARG(); if (get_unsigned(&key, *argv, 0)) invarg(*argv, "invalid key"); instr->mir_instr[c].mir_fwd.ml_type = MPLS_LABEL_KEY; instr->mir_instr[c].mir_fwd.u.ml_key = key; instr->mir_instr[c].mir_opcode = MPLS_OP_FWD; } else if (strcmp(*argv, "pop") == 0) { if (direction == MPLS_OUT) invarg(*argv, "invalid NHLFE instruction"); instr->mir_instr[c].mir_opcode = MPLS_OP_POP; } else if (strcmp(*argv, "peek") == 0) { if (direction == MPLS_OUT) invarg(*argv, "invalid NHLFE instruction"); instr->mir_instr[c].mir_opcode = MPLS_OP_PEEK; } else if (strcmp(*argv, "deliver") == 0) { if (direction == MPLS_OUT) invarg(*argv, "invalid NHLFE instruction"); instr->mir_instr[c].mir_opcode = MPLS_OP_DLV; } else if (strcmp(*argv, "set-dscp") == 0) { __u32 dscp; if (direction == MPLS_OUT) invarg(*argv, "invalid NHLFE instruction"); NEXT_ARG(); if (get_unsigned(&dscp, *argv, 0)) invarg(*argv, "invalid DSCP"); instr->mir_instr[c].mir_opcode = MPLS_OP_SET_DS; instr->mir_instr[c].mir_set_ds = dscp; } else if (strcmp(*argv, "set-tcindex") == 0) { __u32 tcindex; NEXT_ARG(); if (get_unsigned(&tcindex, *argv, 0)) invarg(*argv, "invalid TCINDEX"); instr->mir_instr[c].mir_opcode = MPLS_OP_SET_TC; instr->mir_instr[c].mir_set_tc = tcindex; } else if (strcmp(*argv, "set-exp") == 0) { __u32 exp; NEXT_ARG(); if (get_unsigned(&exp, *argv, 0)) invarg(*argv, "invalid EXP"); instr->mir_instr[c].mir_opcode = MPLS_OP_SET_EXP; instr->mir_instr[c].mir_set_exp = exp; } else if (strcmp(*argv, "set-rx-if") == 0) { if (direction == MPLS_OUT) invarg(*argv, "invalid NHLFE instruction"); NEXT_ARG(); instr->mir_instr[c].mir_opcode = MPLS_OP_SET_RX; instr->mir_instr[c].mir_set_rx =ll_name_to_index(*argv); } else if (strcmp(*argv, "expfwd") == 0) { int done = 0; unsigned int exp; unsigned int key; do { NEXT_ARG(); if (get_unsigned(&exp, *argv, 0)) { done = 1; break; } NEXT_ARG(); if (get_unsigned(&key, *argv, 0)) { done = 1; break; } instr->mir_instr[c].mir_exp_fwd.ef_key[exp] = key; } while (!done); PREV_ARG(); instr->mir_instr[c].mir_opcode = MPLS_OP_EXP_FWD; } else if (strcmp(*argv, "exp2tc") == 0) { int done = 0; unsigned int exp; unsigned int tcindex; do { NEXT_ARG(); if (get_unsigned(&exp, *argv, 0)) { done = 1; break; } NEXT_ARG(); if (get_unsigned(&tcindex, *argv, 0)) { done = 1; break; } instr->mir_instr[c].mir_exp2tc.e2t[exp] = tcindex; } while (!done); PREV_ARG(); instr->mir_instr[c].mir_opcode = MPLS_OP_EXP2TC; } else if (strcmp(*argv, "exp2ds") == 0) { int done = 0; unsigned int exp; unsigned int dscp; if (direction == MPLS_OUT) invarg(*argv, "invalid NHLFE instruction"); do { NEXT_ARG(); if (get_unsigned(&exp, *argv, 0)) { done = 1; break; } NEXT_ARG(); if (get_unsigned(&dscp, *argv, 0)) { done = 1; break; } instr->mir_instr[c].mir_exp2ds.e2d[exp] = dscp; } while (!done); PREV_ARG(); instr->mir_instr[c].mir_opcode = MPLS_OP_EXP2DS; } else if (strcmp(*argv, "nffwd") == 0) { int done = 0; unsigned int nfmark; unsigned int key; unsigned int mask; NEXT_ARG(); if (!get_unsigned(&mask, *argv, 0)) { instr->mir_instr[c].mir_nf_fwd.nf_mask = mask; do { NEXT_ARG(); if (get_unsigned(&nfmark, *argv, 0)) { done = 1; break; } NEXT_ARG(); if (get_unsigned(&key, *argv, 0)) { done = 1; break; } instr->mir_instr[c].mir_nf_fwd.nf_key[nfmark] = key; } while (!done); } PREV_ARG(); instr->mir_instr[c].mir_opcode = MPLS_OP_NF_FWD; } else if (strcmp(*argv, "nf2exp") == 0) { int done = 0; unsigned int nfmark; unsigned int exp; unsigned int mask; NEXT_ARG(); if (!get_unsigned(&mask, *argv, 0)) { instr->mir_instr[c].mir_nf2exp.n2e_mask = mask; do { NEXT_ARG(); if (get_unsigned(&nfmark, *argv, 0)) { done = 1; break; } NEXT_ARG(); if (get_unsigned(&exp, *argv, 0)) { done = 1; break; } instr->mir_instr[c].mir_nf2exp.n2e[nfmark] = exp; } while (!done); } PREV_ARG(); instr->mir_instr[c].mir_opcode = MPLS_OP_NF2EXP; } else if (strcmp(*argv, "tc2exp") == 0) { int done = 0; unsigned int tcindex; unsigned int exp; unsigned int mask; NEXT_ARG(); if (!get_unsigned(&mask, *argv, 0)) { instr->mir_instr[c].mir_tc2exp.t2e_mask = mask; do { NEXT_ARG(); if (get_unsigned(&tcindex, *argv, 0)) { done = 1; break; } NEXT_ARG(); if (get_unsigned(&exp, *argv, 0)) { done = 1; break; } instr->mir_instr[c].mir_tc2exp.t2e[tcindex] = exp; } while (!done); } PREV_ARG(); instr->mir_instr[c].mir_opcode = MPLS_OP_TC2EXP; } else if (strcmp(*argv, "ds2exp") == 0) { int done = 0; unsigned int dscp; unsigned int exp; unsigned int mask; if (direction == MPLS_IN) invarg(*argv, "invalid ILM instruction"); NEXT_ARG(); if (!get_unsigned(&mask, *argv, 0)) { instr->mir_instr[c].mir_ds2exp.d2e_mask = mask; do { NEXT_ARG(); if (get_unsigned(&dscp, *argv, 0)) { done = 1; break; } NEXT_ARG(); if (get_unsigned(&exp, *argv, 0)) { done = 1; break; } instr->mir_instr[c].mir_ds2exp.d2e[dscp] = exp; } while (!done); } PREV_ARG(); instr->mir_instr[c].mir_opcode = MPLS_OP_DS2EXP; } else if (strcmp(*argv, "dsfwd") == 0) { int done = 0; unsigned int dscp; unsigned int key; unsigned int mask; NEXT_ARG(); if (!get_unsigned(&mask, *argv, 0)) { instr->mir_instr[c].mir_ds_fwd.df_mask = mask; do { NEXT_ARG(); if (get_unsigned(&dscp, *argv, 0)) { done = 1; break; } NEXT_ARG(); if (get_unsigned(&key, *argv, 0)) { done = 1; break; } instr->mir_instr[c].mir_ds_fwd.df_key[dscp] = key; } while (!done); } PREV_ARG(); instr->mir_instr[c].mir_opcode = MPLS_OP_DS_FWD; } else { invarg(*argv, "invalid mpls instruction"); } argc--; argv++; c++; } instr->mir_instr_length = c; instr->mir_direction = direction; *pargc = argc; *pargv = argv; }
static int parse_bpf(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { char **argv = *argv_p, bpf_name[256]; struct rtattr *tail; struct tc_act_bpf parm = { 0 }; struct sock_filter bpf_ops[BPF_MAXINSNS]; bool ebpf = false, seen_run = false; const char *bpf_uds_name = NULL; const char *bpf_sec_name = NULL; char *bpf_obj = NULL; int argc = *argc_p, ret = 0; __u16 bpf_len = 0; __u32 bpf_fd = 0; if (matches(*argv, "bpf") != 0) return -1; NEXT_ARG(); while (argc > 0) { if (matches(*argv, "run") == 0) { bool from_file; int ret; NEXT_ARG(); opt_bpf: bpf_sec_name = bpf_default_section(bpf_type); seen_run = true; if (strcmp(*argv, "bytecode-file") == 0 || strcmp(*argv, "bcf") == 0) { from_file = true; } else if (strcmp(*argv, "bytecode") == 0 || strcmp(*argv, "bc") == 0) { from_file = false; } else if (strcmp(*argv, "object-file") == 0 || strcmp(*argv, "obj") == 0) { ebpf = true; } else { fprintf(stderr, "unexpected \"%s\"\n", *argv); explain(); return -1; } NEXT_ARG(); if (ebpf) { bpf_obj = *argv; NEXT_ARG(); if (strcmp(*argv, "section") == 0 || strcmp(*argv, "sec") == 0) { NEXT_ARG(); bpf_sec_name = *argv; NEXT_ARG(); } if (strcmp(*argv, "export") == 0 || strcmp(*argv, "exp") == 0) { NEXT_ARG(); bpf_uds_name = *argv; NEXT_ARG(); } PREV_ARG(); } ret = ebpf ? bpf_open_object(bpf_obj, bpf_type, bpf_sec_name) : bpf_parse_ops(argc, argv, bpf_ops, from_file); if (ret < 0) { fprintf(stderr, "%s\n", ebpf ? "Could not load object" : "Illegal \"bytecode\""); return -1; } if (ebpf) { bpf_obj = basename(bpf_obj); snprintf(bpf_name, sizeof(bpf_name), "%s:[%s]", bpf_obj, bpf_sec_name); bpf_fd = ret; } else { bpf_len = ret; } } else if (matches(*argv, "help") == 0) { usage(); } else { if (!seen_run) goto opt_bpf; break; } argc--; argv++; } parm.action = TC_ACT_PIPE; if (argc) { if (matches(*argv, "reclassify") == 0) { parm.action = TC_ACT_RECLASSIFY; argc--; argv++; } else if (matches(*argv, "pipe") == 0) { parm.action = TC_ACT_PIPE; argc--; argv++; } else if (matches(*argv, "drop") == 0 || matches(*argv, "shot") == 0) { parm.action = TC_ACT_SHOT; argc--; argv++; } else if (matches(*argv, "continue") == 0) { parm.action = TC_ACT_UNSPEC; argc--; argv++; } else if (matches(*argv, "pass") == 0) { parm.action = TC_ACT_OK; argc--; argv++; } } if (argc) { if (matches(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&parm.index, *argv, 10)) { fprintf(stderr, "bpf: Illegal \"index\"\n"); return -1; } argc--; argv++; } } if ((!bpf_len && !ebpf) || (!bpf_fd && ebpf)) { fprintf(stderr, "bpf: Bytecode needs to be passed\n"); explain(); return -1; } tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, tca_id, NULL, 0); addattr_l(n, MAX_MSG, TCA_ACT_BPF_PARMS, &parm, sizeof(parm)); if (ebpf) { addattr32(n, MAX_MSG, TCA_ACT_BPF_FD, bpf_fd); addattrstrz(n, MAX_MSG, TCA_ACT_BPF_NAME, bpf_name); } else { addattr16(n, MAX_MSG, TCA_ACT_BPF_OPS_LEN, bpf_len); addattr_l(n, MAX_MSG, TCA_ACT_BPF_OPS, &bpf_ops, bpf_len * sizeof(struct sock_filter)); } tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; *argc_p = argc; *argv_p = argv; if (bpf_uds_name) ret = bpf_send_map_fds(bpf_uds_name, bpf_obj); return ret; }