diff --git a/frr/rt_grout.c b/frr/rt_grout.c index 3a9a3a06d..87502fea4 100644 --- a/frr/rt_grout.c +++ b/frr/rt_grout.c @@ -190,6 +190,15 @@ static int grout_gr_nexthop_to_frr_nexthop(struct gr_nexthop *gr_nh, struct nexthop *nh, int *nh_family) { size_t sz; + if (gr_nh->type == GR_NH_T_BLACKHOLE || gr_nh->type == GR_NH_T_REJECT) { + nh->vrf_id = gr_nh->vrf_id; + nh->type = NEXTHOP_TYPE_BLACKHOLE; + nh->bh_type = gr_nh->type == GR_NH_T_REJECT ? BLACKHOLE_REJECT : BLACKHOLE_NULL; + *nh_family = AF_UNSPEC; + nh->weight = 1; + return 0; + } + if (gr_nh->type != GR_NH_T_L3) { gr_log_err("sync nexthop not L3 from grout is not supported"); return -1; @@ -781,10 +790,6 @@ enum zebra_dplane_result grout_add_del_nexthop(struct zebra_dplane_ctx *ctx) { } nh = dplane_ctx_get_nhe_ng(ctx)->nexthop; - if (nh->type == NEXTHOP_TYPE_BLACKHOLE) { - gr_log_err("impossible to add/del blackhole nexthop (not supported)"); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } if (nh->nh_srv6) { gr_log_err("impossible to add/del srv6 nexthop (not supported)"); return ZEBRA_DPLANE_REQUEST_SUCCESS; @@ -820,11 +825,12 @@ enum zebra_dplane_result grout_add_del_nexthop(struct zebra_dplane_ctx *ctx) { else gr_nh->af = GR_AF_IP6; - if (!nh->ifindex) { + if (nh->type != NEXTHOP_TYPE_BLACKHOLE && !nh->ifindex) { gr_log_err("impossible to add/del nexthop in grout that does not have an ifindex"); return ZEBRA_DPLANE_REQUEST_FAILURE; + } else { + gr_nh->iface_id = nh->ifindex; } - gr_nh->iface_id = nh->ifindex; switch (nh->type) { case NEXTHOP_TYPE_IPV4: @@ -843,6 +849,12 @@ enum zebra_dplane_result grout_add_del_nexthop(struct zebra_dplane_ctx *ctx) { gr_nh->af = GR_AF_UNSPEC; gr_log_debug("add nexthop id %u with ifindex %u", nh_id, gr_nh->iface_id); break; + case NEXTHOP_TYPE_BLACKHOLE: + gr_nh->type = nh->bh_type == BLACKHOLE_REJECT ? GR_NH_T_REJECT : GR_NH_T_BLACKHOLE; + gr_nh->af = GR_AF_UNSPEC; + gr_nh->iface_id = GR_IFACE_ID_UNDEF; + gr_log_debug("add nexthop id %u with type %s", nh_id, gr_nh_type_name(gr_nh)); + break; default: gr_log_err("impossible to add nexthop %u (type %u not supported)", nh_id, nh->type); return ZEBRA_DPLANE_REQUEST_FAILURE; diff --git a/modules/infra/api/gr_nexthop.h b/modules/infra/api/gr_nexthop.h index b433552ea..6c62ce5d6 100644 --- a/modules/infra/api/gr_nexthop.h +++ b/modules/infra/api/gr_nexthop.h @@ -30,6 +30,8 @@ typedef enum : uint8_t { GR_NH_T_SR6_OUTPUT, GR_NH_T_SR6_LOCAL, GR_NH_T_DNAT, + GR_NH_T_BLACKHOLE, + GR_NH_T_REJECT, } gr_nh_type_t; // Route install origin values shared by IPv4 and IPv6. @@ -149,6 +151,10 @@ static inline const char *gr_nh_type_name(const struct gr_nexthop *nh) { return "SRv6-local"; case GR_NH_T_DNAT: return "DNAT"; + case GR_NH_T_BLACKHOLE: + return "blackhole"; + case GR_NH_T_REJECT: + return "reject"; } return "?"; } diff --git a/modules/infra/api/nexthop.c b/modules/infra/api/nexthop.c index 5cc1742c5..2849cf1c3 100644 --- a/modules/infra/api/nexthop.c +++ b/modules/infra/api/nexthop.c @@ -39,50 +39,77 @@ static struct gr_api_handler config_set_handler = { .callback = nh_config_set, }; -static struct api_out nh_add(const void *request, void ** /*response*/) { - const struct gr_nh_add_req *req = request; - const struct nexthop_af_ops *ops; - struct gr_nexthop base = req->nh; - struct nexthop *nh = NULL; +static int nh_add_blackhole(struct gr_nexthop *base) { + base->state = GR_NH_S_REACHABLE; + base->flags |= GR_NH_F_STATIC; + base->af = GR_AF_UNSPEC; + base->iface_id = GR_IFACE_ID_UNDEF; + return 0; +} + +static int nh_add_l3(struct gr_nexthop *base) { struct iface *iface; - int ret; - base.flags = 0; - switch (base.af) { + switch (base->af) { case GR_AF_IP4: - if (base.ipv4 == 0) - return api_out(EDESTADDRREQ, 0); - + if (base->ipv4 == 0) + return -EDESTADDRREQ; break; case GR_AF_IP6: - if (rte_ipv6_addr_is_unspec(&base.ipv6)) - return api_out(EDESTADDRREQ, 0); + if (rte_ipv6_addr_is_unspec(&base->ipv6)) + return -EDESTADDRREQ; break; case GR_AF_UNSPEC: - if (base.ipv4 || !rte_ipv6_addr_is_unspec(&base.ipv6)) - return api_out(EINVAL, 0); + if (base->ipv4 || !rte_ipv6_addr_is_unspec(&base->ipv6)) + return -EINVAL; - base.flags |= GR_NH_F_LINK | GR_NH_F_STATIC; + base->flags |= GR_NH_F_LINK | GR_NH_F_STATIC; break; default: - return api_out(ENOPROTOOPT, 0); + return -ENOPROTOOPT; } - iface = iface_from_id(base.iface_id); + iface = iface_from_id(base->iface_id); if (iface == NULL) - return api_out(errno, 0); + return -errno; + + base->vrf_id = iface->vrf_id; + base->state = GR_NH_S_NEW; + if (!rte_is_zero_ether_addr(&base->mac)) { + if (base->af == GR_AF_UNSPEC) + return -EINVAL; + + base->state = GR_NH_S_REACHABLE; + base->flags |= GR_NH_F_STATIC; + } + return 0; +} - base.vrf_id = iface->vrf_id; - base.type = GR_NH_T_L3; - base.state = GR_NH_S_NEW; - if (!rte_is_zero_ether_addr(&base.mac)) { - if (base.af == GR_AF_UNSPEC) - return api_out(EINVAL, 0); +static struct api_out nh_add(const void *request, void ** /*response*/) { + const struct gr_nh_add_req *req = request; + const struct nexthop_af_ops *ops; + struct gr_nexthop base = req->nh; + struct nexthop *nh = NULL; + int ret; - base.state = GR_NH_S_REACHABLE; - base.flags |= GR_NH_F_STATIC; + base.flags = 0; + switch (base.type) { + case GR_NH_T_BLACKHOLE: + case GR_NH_T_REJECT: + ret = nh_add_blackhole(&base); + break; + case GR_NH_T_L3: + case GR_NH_T_SR6_OUTPUT: + case GR_NH_T_SR6_LOCAL: + case GR_NH_T_DNAT: + ret = nh_add_l3(&base); + break; + default: + return api_out(EINVAL, 0); } + if (ret < 0) + return api_out(-ret, 0); if (base.nh_id != GR_NH_ID_UNSET) nh = nexthop_lookup_by_id(base.nh_id); @@ -151,7 +178,8 @@ static struct api_out nh_del(const void *request, void ** /*response*/) { return api_out(ENOENT, 0); } - if (nh->type != GR_NH_T_L3 || (nh->flags & addr_flags) == addr_flags || nh->ref_count > 1) + if ((nh->type != GR_NH_T_L3 && nh->type != GR_NH_T_BLACKHOLE && nh->type != GR_NH_T_REJECT) + || (nh->flags & addr_flags) == addr_flags || nh->ref_count > 1) return api_out(EBUSY, 0); ops = nexthop_af_ops_get(nh->af); diff --git a/modules/infra/cli/nexthop.c b/modules/infra/cli/nexthop.c index 337a4245f..56c1e8e0f 100644 --- a/modules/infra/cli/nexthop.c +++ b/modules/infra/cli/nexthop.c @@ -59,12 +59,26 @@ static cmd_status_t show_config(const struct gr_api_client *c, const struct ec_p } static cmd_status_t nh_add(const struct gr_api_client *c, const struct ec_pnode *p) { - struct gr_nh_add_req req = {.exist_ok = true, .nh.origin = GR_NH_ORIGIN_USER}; + struct gr_nh_add_req req = { + .exist_ok = true, + .nh.origin = GR_NH_ORIGIN_USER, + .nh.type = GR_NH_T_L3, + }; struct gr_iface iface; if (arg_u32(p, "ID", &req.nh.nh_id) < 0 && errno != ENOENT) return CMD_ERROR; + if (arg_str(p, "blackhole") != NULL) { + req.nh.type = GR_NH_T_BLACKHOLE; + goto send; + } + + if (arg_str(p, "reject") != NULL) { + req.nh.type = GR_NH_T_REJECT; + goto send; + } + switch (arg_ip4(p, "IP", &req.nh.ipv4)) { case 0: req.nh.af = GR_AF_IP4; @@ -85,7 +99,7 @@ static cmd_status_t nh_add(const struct gr_api_client *c, const struct ec_pnode if (arg_eth_addr(p, "MAC", &req.nh.mac) < 0 && errno != ENOENT) return CMD_ERROR; - +send: if (gr_api_client_send_recv(c, GR_NH_ADD, sizeof(req), &req, NULL) < 0) return CMD_ERROR; @@ -245,13 +259,15 @@ static int ctx_init(struct ec_node *root) { ret = CLI_COMMAND( CLI_CONTEXT(root, CTX_ADD), - "nexthop [id ID] [address IP] iface IFACE [mac MAC]", + "nexthop [id ID] ([address IP] iface IFACE [mac MAC])|blackhole|reject", nh_add, "Add a new next hop.", with_help("IPv4/6 address.", ec_node_re("IP", IP_ANY_RE)), with_help("Ethernet address.", ec_node_re("MAC", ETH_ADDR_RE)), with_help("Nexthop ID.", ec_node_uint("ID", 1, UINT32_MAX - 1, 10)), - with_help("Output interface.", ec_node_dyn("IFACE", complete_iface_names, NULL)) + with_help("Output interface.", ec_node_dyn("IFACE", complete_iface_names, NULL)), + with_help("Blackhole nexthop.", ec_node_str("blackhole", "blackhole")), + with_help("Reject nexthop sending ICMP UNREACH.", ec_node_str("reject", "reject")) ); if (ret < 0) return ret; diff --git a/modules/infra/control/nexthop.c b/modules/infra/control/nexthop.c index 8a65c9631..910b49e9d 100644 --- a/modules/infra/control/nexthop.c +++ b/modules/infra/control/nexthop.c @@ -312,6 +312,8 @@ void nexthop_type_ops_register(gr_nh_type_t type, const struct nexthop_type_ops case GR_NH_T_SR6_OUTPUT: case GR_NH_T_SR6_LOCAL: case GR_NH_T_DNAT: + case GR_NH_T_BLACKHOLE: + case GR_NH_T_REJECT: if (ops == NULL || (ops->free == NULL && ops->equal == NULL)) ABORT("invalid type ops"); if (type_ops[type] != NULL) @@ -336,6 +338,8 @@ struct nexthop *nexthop_new(const struct gr_nexthop *base) { case GR_NH_T_SR6_OUTPUT: case GR_NH_T_SR6_LOCAL: case GR_NH_T_DNAT: + case GR_NH_T_BLACKHOLE: + case GR_NH_T_REJECT: break; default: ABORT("invalid nexthop type %hhu", base->type); diff --git a/modules/ip/cli/route.c b/modules/ip/cli/route.c index f53923ab6..1c649439b 100644 --- a/modules/ip/cli/route.c +++ b/modules/ip/cli/route.c @@ -79,20 +79,25 @@ static cmd_status_t route4_list(const struct gr_api_client *c, const struct ec_p struct gr_iface iface; scols_line_sprintf(line, 0, "%u", route->vrf_id); scols_line_sprintf(line, 1, IP4_F "/%hhu", &route->dest.ip, route->dest.prefixlen); - switch (route->nh.af) { - case GR_AF_UNSPEC: - if (iface_from_id(c, route->nh.iface_id, &iface) < 0) - scols_line_sprintf(line, 2, "%u", route->nh.iface_id); - else - scols_line_sprintf(line, 2, "%s", iface.name); - break; - case GR_AF_IP4: - scols_line_sprintf(line, 2, IP4_F, &route->nh.ipv4); - break; - case GR_AF_IP6: - scols_line_sprintf(line, 2, IP6_F, &route->nh.ipv6); - break; - } + if (route->nh.type == GR_NH_T_BLACKHOLE) + scols_line_sprintf(line, 2, "blackhole"); + else if (route->nh.type == GR_NH_T_REJECT) + scols_line_sprintf(line, 2, "reject"); + else + switch (route->nh.af) { + case GR_AF_UNSPEC: + if (iface_from_id(c, route->nh.iface_id, &iface) < 0) + scols_line_sprintf(line, 2, "%u", route->nh.iface_id); + else + scols_line_sprintf(line, 2, "%s", iface.name); + break; + case GR_AF_IP4: + scols_line_sprintf(line, 2, IP4_F, &route->nh.ipv4); + break; + case GR_AF_IP6: + scols_line_sprintf(line, 2, IP6_F, &route->nh.ipv6); + break; + } scols_line_sprintf(line, 3, "%s", gr_nh_origin_name(route->origin)); if (route->nh.nh_id != GR_NH_ID_UNSET) scols_line_sprintf(line, 4, "%u", route->nh.nh_id); diff --git a/modules/ip/control/route.c b/modules/ip/control/route.c index 3b54fd2fd..7ab518ff2 100644 --- a/modules/ip/control/route.c +++ b/modules/ip/control/route.c @@ -265,7 +265,9 @@ static struct api_out route4_del(const void *request, void ** /*response*/) { int ret; nh = rib4_lookup(req->vrf_id, req->dest.ip); - ret = rib4_delete(req->vrf_id, req->dest.ip, req->dest.prefixlen, GR_NH_T_L3); + ret = rib4_delete( + req->vrf_id, req->dest.ip, req->dest.prefixlen, nh ? nh->type : GR_NH_T_L3 + ); if (ret == -ENOENT && req->missing_ok) ret = 0; diff --git a/modules/ip/datapath/arp_output_request.c b/modules/ip/datapath/arp_output_request.c index 8827cd975..4ff8f8f16 100644 --- a/modules/ip/datapath/arp_output_request.c +++ b/modules/ip/datapath/arp_output_request.c @@ -22,6 +22,8 @@ enum { OUTPUT = 0, + BLACKHOLE, + REJECT, ERROR, EDGE_COUNT, }; @@ -61,6 +63,16 @@ static uint16_t arp_output_request_process( for (unsigned i = 0; i < n_objs; i++) { mbuf = objs[i]; nh = control_input_mbuf_data(mbuf)->data; + + if (nh->type == GR_NH_T_BLACKHOLE) { + edge = BLACKHOLE; + goto next; + } + if (nh->type == GR_NH_T_REJECT) { + edge = REJECT; + goto next; + } + local = addr4_get_preferred(nh->iface_id, nh->ipv4); if (local == NULL) { @@ -122,6 +134,8 @@ static struct rte_node_register arp_output_request_node = { .nb_edges = EDGE_COUNT, .next_nodes = { [OUTPUT] = "eth_output", + [BLACKHOLE] = "ip_blackhole", + [REJECT] = "ip_admin_prohibited", [ERROR] = "arp_output_error", }, }; diff --git a/modules/ip/datapath/icmp_output.c b/modules/ip/datapath/icmp_output.c index f82615dc1..864873c81 100644 --- a/modules/ip/datapath/icmp_output.c +++ b/modules/ip/datapath/icmp_output.c @@ -15,6 +15,8 @@ enum { OUTPUT = 0, + BLACKHOLE, + REJECT, NO_HEADROOM, NO_ROUTE, EDGE_COUNT, @@ -51,11 +53,21 @@ icmp_output_process(struct rte_graph *graph, struct rte_node *node, void **objs, edge = NO_ROUTE; goto next; } + if (nh->type == GR_NH_T_BLACKHOLE) { + edge = BLACKHOLE; + goto next; + } else if (nh->type == GR_NH_T_REJECT) { + edge = REJECT; + goto next; + } o = ip_output_mbuf_data(mbuf); o->nh = nh; o->iface = NULL; edge = OUTPUT; next: + if (gr_mbuf_is_traced(mbuf)) + gr_mbuf_trace_add(mbuf, node, 0); + rte_node_enqueue_x1(graph, node, edge, mbuf); } @@ -70,6 +82,8 @@ static struct rte_node_register icmp_output_node = { .nb_edges = EDGE_COUNT, .next_nodes = { [OUTPUT] = "ip_output", + [BLACKHOLE] = "ip_blackhole", + [REJECT] = "ip_admin_prohibited", [NO_HEADROOM] = "error_no_headroom", [NO_ROUTE] = "icmp_output_no_route", }, @@ -82,3 +96,4 @@ static struct gr_node_info icmp_output_info = { GR_NODE_REGISTER(icmp_output_info); GR_DROP_REGISTER(icmp_output_no_route); +GR_DROP_REGISTER(ip_admin_prohibited); diff --git a/modules/ip/datapath/ip_input.c b/modules/ip/datapath/ip_input.c index 0d24f10d4..3ec427d78 100644 --- a/modules/ip/datapath/ip_input.c +++ b/modules/ip/datapath/ip_input.c @@ -158,6 +158,8 @@ ip_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, ui static void ip_input_register(void) { gr_eth_input_add_type(RTE_BE16(RTE_ETHER_TYPE_IPV4), "ip_input"); + ip_input_register_nexthop_type(GR_NH_T_BLACKHOLE, "ip_blackhole"); + ip_input_register_nexthop_type(GR_NH_T_REJECT, "ip_error_dest_unreach"); } static struct rte_node_register input_node = { @@ -190,6 +192,7 @@ GR_DROP_REGISTER(ip_input_bad_checksum); GR_DROP_REGISTER(ip_input_bad_length); GR_DROP_REGISTER(ip_input_bad_version); GR_DROP_REGISTER(ip_input_other_host); +GR_DROP_REGISTER(ip_blackhole); #ifdef __GROUT_UNIT_TEST__ #include diff --git a/modules/ip6/cli/route.c b/modules/ip6/cli/route.c index f02d7e4e1..83c7b2a04 100644 --- a/modules/ip6/cli/route.c +++ b/modules/ip6/cli/route.c @@ -79,20 +79,25 @@ static cmd_status_t route6_list(const struct gr_api_client *c, const struct ec_p struct gr_iface iface; scols_line_sprintf(line, 0, "%u", route->vrf_id); scols_line_sprintf(line, 1, IP6_F "/%hhu", &route->dest, route->dest.prefixlen); - switch (route->nh.af) { - case GR_AF_UNSPEC: - if (iface_from_id(c, route->nh.iface_id, &iface) < 0) - scols_line_sprintf(line, 2, "%u", route->nh.iface_id); - else - scols_line_sprintf(line, 2, "%s", iface.name); - break; - case GR_AF_IP4: - scols_line_sprintf(line, 2, IP4_F, &route->nh.ipv4); - break; - case GR_AF_IP6: - scols_line_sprintf(line, 2, IP6_F, &route->nh.ipv6); - break; - } + if (route->nh.type == GR_NH_T_BLACKHOLE) + scols_line_sprintf(line, 2, "blackhole"); + else if (route->nh.type == GR_NH_T_REJECT) + scols_line_sprintf(line, 2, "reject"); + else + switch (route->nh.af) { + case GR_AF_UNSPEC: + if (iface_from_id(c, route->nh.iface_id, &iface) < 0) + scols_line_sprintf(line, 2, "%u", route->nh.iface_id); + else + scols_line_sprintf(line, 2, "%s", iface.name); + break; + case GR_AF_IP4: + scols_line_sprintf(line, 2, IP4_F, &route->nh.ipv4); + break; + case GR_AF_IP6: + scols_line_sprintf(line, 2, IP6_F, &route->nh.ipv6); + break; + } scols_line_sprintf(line, 3, "%s", gr_nh_origin_name(route->origin)); if (route->nh.nh_id != GR_NH_ID_UNSET) scols_line_sprintf(line, 4, "%u", route->nh.nh_id); diff --git a/modules/ip6/control/route.c b/modules/ip6/control/route.c index 67f9c1108..5420f4e79 100644 --- a/modules/ip6/control/route.c +++ b/modules/ip6/control/route.c @@ -290,7 +290,11 @@ static struct api_out route6_del(const void *request, void ** /*response*/) { nh = rib6_lookup(req->vrf_id, GR_IFACE_ID_UNDEF, &req->dest.ip); ret = rib6_delete( - req->vrf_id, GR_IFACE_ID_UNDEF, &req->dest.ip, req->dest.prefixlen, GR_NH_T_L3 + req->vrf_id, + GR_IFACE_ID_UNDEF, + &req->dest.ip, + req->dest.prefixlen, + nh ? nh->type : GR_NH_T_L3 ); if (ret == -ENOENT && req->missing_ok) ret = 0; diff --git a/modules/ip6/datapath/icmp6_output.c b/modules/ip6/datapath/icmp6_output.c index 70070fa3b..c2f144807 100644 --- a/modules/ip6/datapath/icmp6_output.c +++ b/modules/ip6/datapath/icmp6_output.c @@ -16,6 +16,8 @@ enum { OUTPUT = 0, + BLACKHOLE, + REJECT, NO_HEADROOM, NO_ROUTE, EDGE_COUNT, @@ -65,6 +67,13 @@ static uint16_t icmp6_output_process( edge = NO_ROUTE; goto next; } + if (nh->type == GR_NH_T_BLACKHOLE) { + edge = BLACKHOLE; + goto next; + } else if (nh->type == GR_NH_T_REJECT) { + edge = REJECT; + goto next; + } o = ip6_output_mbuf_data(mbuf); o->nh = nh; o->iface = d->iface; @@ -84,6 +93,8 @@ static struct rte_node_register icmp6_output_node = { .nb_edges = EDGE_COUNT, .next_nodes = { [OUTPUT] = "ip6_output", + [BLACKHOLE] = "ip6_blackhole", + [REJECT] = "ip6_admin_prohibited", [NO_HEADROOM] = "error_no_headroom", [NO_ROUTE] = "icmp6_output_no_route", }, @@ -96,4 +107,5 @@ static struct gr_node_info icmp6_output_info = { GR_NODE_REGISTER(icmp6_output_info); -GR_DROP_REGISTER(icmp6_output_no_route) +GR_DROP_REGISTER(icmp6_output_no_route); +GR_DROP_REGISTER(ip6_admin_prohibited); diff --git a/modules/ip6/datapath/ip6_input.c b/modules/ip6/datapath/ip6_input.c index 4b60a9d0d..6a29e31fa 100644 --- a/modules/ip6/datapath/ip6_input.c +++ b/modules/ip6/datapath/ip6_input.c @@ -151,6 +151,8 @@ ip6_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, u static void ip6_input_register(void) { gr_eth_input_add_type(RTE_BE16(RTE_ETHER_TYPE_IPV6), "ip6_input"); + ip6_input_register_nexthop_type(GR_NH_T_BLACKHOLE, "ip6_blackhole"); + ip6_input_register_nexthop_type(GR_NH_T_REJECT, "ip6_error_dest_unreach"); } static struct rte_node_register input_node = { @@ -185,6 +187,7 @@ GR_DROP_REGISTER(ip6_input_other_host); GR_DROP_REGISTER(ip6_input_bad_version); GR_DROP_REGISTER(ip6_input_bad_addr); GR_DROP_REGISTER(ip6_input_bad_length); +GR_DROP_REGISTER(ip6_blackhole); #ifdef __GROUT_UNIT_TEST__ #include diff --git a/modules/ip6/datapath/ndp_ns_output.c b/modules/ip6/datapath/ndp_ns_output.c index 95f0ae271..266d00729 100644 --- a/modules/ip6/datapath/ndp_ns_output.c +++ b/modules/ip6/datapath/ndp_ns_output.c @@ -24,6 +24,8 @@ enum { OUTPUT = 0, + BLACKHOLE, + REJECT, ERROR, EDGE_COUNT, }; @@ -69,6 +71,15 @@ static uint16_t ndp_ns_output_process( next = ERROR; goto next; } + if (nh->type == GR_NH_T_BLACKHOLE) { + next = BLACKHOLE; + goto next; + } + if (nh->type == GR_NH_T_REJECT) { + next = REJECT; + goto next; + } + local = addr6_get_preferred(nh->iface_id, &nh->ipv6); if (local == NULL) { next = ERROR; @@ -103,7 +114,7 @@ static uint16_t ndp_ns_output_process( next = OUTPUT; next: if (gr_mbuf_is_traced(mbuf)) { - if (next == ERROR) { + if (next != OUTPUT) { gr_mbuf_trace_add(mbuf, node, 0); } else { uint8_t trace_len = RTE_MIN(payload_len, GR_TRACE_ITEM_MAX_LEN); @@ -127,6 +138,8 @@ static struct rte_node_register node = { .nb_edges = EDGE_COUNT, .next_nodes = { [OUTPUT] = "icmp6_output", + [BLACKHOLE] = "ip6_blackhole", + [REJECT] = "ip6_admin_prohibited", [ERROR] = "ndp_ns_output_error", }, };