diff --git a/lib/zclient.c b/lib/zclient.c index 777f6fcf9b..2cac71ac45 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1340,6 +1340,16 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr) case NEXTHOP_TYPE_BLACKHOLE: break; } + STREAM_GETC(s, nhr->nexthops[i].label_num); + if (nhr->nexthops[i].label_num > MPLS_MAX_LABELS) { + zlog_warn("%s: invalid number of MPLS labels (%u)", + __func__, nhr->nexthops[i].label_num); + return false; + } + if (nhr->nexthops[i].label_num) + STREAM_GET(&nhr->nexthops[i].labels[0], s, + nhr->nexthops[i].label_num + * sizeof(mpls_label_t)); } return true; diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 3065ad19c3..4d19484a64 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -39,6 +39,46 @@ extern uint32_t total_routes; extern uint32_t installed_routes; extern uint32_t removed_routes; +DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, + "sharp watch nexthop X:X::X:X$nhop", + "Sharp routing Protocol\n" + "Watch for changes\n" + "Watch for nexthop changes\n" + "The v6 nexthop to signal for watching\n") +{ + struct prefix p; + + memset(&p, 0, sizeof(p)); + + p.prefixlen = 128; + memcpy(&p.u.prefix6, &nhop, 16); + p.family = AF_INET6; + + sharp_zebra_nexthop_watch(&p, true); + + return CMD_SUCCESS; +} + +DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, + "sharp watch nexthop A.B.C.D$nhop", + "Sharp routing Protocol\n" + "Watch for changes\n" + "Watch for nexthop changes\n" + "The v4 nexthop to signal for watching\n") +{ + struct prefix p; + + memset(&p, 0, sizeof(p)); + + p.prefixlen = 32; + p.u.prefix4 = nhop; + p.family = AF_INET; + + sharp_zebra_nexthop_watch(&p, true); + + return CMD_SUCCESS; +} + DEFPY (install_routes, install_routes_cmd, "sharp install routes A.B.C.D$start nexthop A.B.C.D$nexthop (1-1000000)$routes", @@ -147,5 +187,7 @@ void sharp_vty_init(void) install_element(ENABLE_NODE, &install_routes_cmd); install_element(ENABLE_NODE, &remove_routes_cmd); install_element(ENABLE_NODE, &vrf_label_cmd); + install_element(ENABLE_NODE, &watch_nexthop_v6_cmd); + install_element(ENABLE_NODE, &watch_nexthop_v4_cmd); return; } diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 8915397c7e..999255e925 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -214,6 +214,65 @@ void route_delete(struct prefix *p) return; } +void sharp_zebra_nexthop_watch(struct prefix *p, bool watch) +{ + int command = ZEBRA_NEXTHOP_REGISTER; + + if (!watch) + command = ZEBRA_NEXTHOP_UNREGISTER; + + zclient_send_rnh(zclient, command, p, true, VRF_DEFAULT); +} + +static int sharp_nexthop_update(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct zapi_route nhr; + char buf[PREFIX_STRLEN]; + int i; + + if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { + zlog_warn("%s: Decode of update failed", __PRETTY_FUNCTION__); + + return 0; + } + + zlog_debug("Received update for %s", + prefix2str(&nhr.prefix, buf, sizeof(buf))); + for (i = 0; i < nhr.nexthop_num; i++) { + struct zapi_nexthop *znh = &nhr.nexthops[i]; + + switch (znh->type) { + case NEXTHOP_TYPE_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV4: + zlog_debug( + "\tNexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d", + inet_ntop(AF_INET, &znh->gate.ipv4.s_addr, buf, + sizeof(buf)), + znh->type, znh->ifindex, znh->vrf_id, + znh->label_num); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + case NEXTHOP_TYPE_IPV6: + zlog_debug( + "\tNexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d", + inet_ntop(AF_INET6, &znh->gate.ipv6, buf, + sizeof(buf)), + znh->type, znh->ifindex, znh->vrf_id, + znh->label_num); + break; + case NEXTHOP_TYPE_IFINDEX: + zlog_debug("\tNexthop IFINDEX: %d, ifindex: %d", + znh->type, znh->ifindex); + break; + case NEXTHOP_TYPE_BLACKHOLE: + zlog_debug("\tNexthop blackhole"); + break; + } + } + return 0; +} + extern struct zebra_privs_t sharp_privs; void sharp_zebra_init(void) @@ -231,4 +290,5 @@ void sharp_zebra_init(void) zclient->interface_address_add = interface_address_add; zclient->interface_address_delete = interface_address_delete; zclient->route_notify_owner = route_notify_owner; + zclient->nexthop_update = sharp_nexthop_update; } diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index 0bba443bd4..0c906fc4ff 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -27,4 +27,5 @@ extern void sharp_zebra_init(void); extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label); extern void route_add(struct prefix *p, struct nexthop *nh); extern void route_delete(struct prefix *p); +extern void sharp_zebra_nexthop_watch(struct prefix *p, bool watch); #endif diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 1868b4676d..8375d45d2f 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -2254,6 +2254,19 @@ void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf, fec_print(rn->info, vty); } +static bool mpls_ftn_update_nexthop(int add, struct nexthop *nexthop, + enum lsp_types_t type, mpls_label_t label) +{ + if (add && nexthop->nh_label_type == ZEBRA_LSP_NONE) + nexthop_add_labels(nexthop, type, 1, &label); + else if (!add && nexthop->nh_label_type == type) + nexthop_del_labels(nexthop); + else + return false; + + return true; +} + /* * Install/uninstall a FEC-To-NHLFE (FTN) binding. */ @@ -2266,6 +2279,7 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, struct route_node *rn; struct route_entry *re; struct nexthop *nexthop; + bool found; /* Lookup table. */ table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST, @@ -2285,6 +2299,7 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, if (re == NULL) return -1; + found = false; for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) { switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: @@ -2297,7 +2312,11 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX && nexthop->ifindex != ifindex) continue; - goto found; + if (!mpls_ftn_update_nexthop(add, nexthop, type, + out_label)) + return 0; + found = true; + break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: if (gtype != NEXTHOP_TYPE_IPV6 @@ -2308,21 +2327,18 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX && nexthop->ifindex != ifindex) continue; - goto found; + if (!mpls_ftn_update_nexthop(add, nexthop, type, + out_label)) + return 0; + found = true; + break; default: break; } } - /* nexthop not found */ - return -1; -found: - if (add && nexthop->nh_label_type == ZEBRA_LSP_NONE) - nexthop_add_labels(nexthop, type, 1, &out_label); - else if (!add && nexthop->nh_label_type == type) - nexthop_del_labels(nexthop); - else - return 0; + if (!found) + return -1; SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index c9fb782ba6..48f9f4f366 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -986,7 +986,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, struct route_entry *re; unsigned long nump; u_char num; - struct nexthop *nexthop; + struct nexthop *nh; struct route_node *rn; int cmd = (type == RNH_IMPORT_CHECK_TYPE) ? ZEBRA_IMPORT_CHECK_UPDATE : ZEBRA_NEXTHOP_UPDATE; @@ -1022,32 +1022,40 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, num = 0; nump = stream_get_endp(s); stream_putc(s, 0); - for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) - if ((CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB) - || CHECK_FLAG(nexthop->flags, - NEXTHOP_FLAG_RECURSIVE)) - && CHECK_FLAG(nexthop->flags, - NEXTHOP_FLAG_ACTIVE)) { - stream_putc(s, nexthop->type); - switch (nexthop->type) { + for (nh = re->ng.nexthop; nh; nh = nh->next) + if ((CHECK_FLAG(nh->flags, NEXTHOP_FLAG_FIB) + || CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) + && CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE)) { + stream_putc(s, nh->type); + switch (nh->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: - stream_put_in_addr(s, - &nexthop->gate.ipv4); - stream_putl(s, nexthop->ifindex); + stream_put_in_addr(s, &nh->gate.ipv4); + stream_putl(s, nh->ifindex); break; case NEXTHOP_TYPE_IFINDEX: - stream_putl(s, nexthop->ifindex); + stream_putl(s, nh->ifindex); break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: - stream_put(s, &nexthop->gate.ipv6, 16); - stream_putl(s, nexthop->ifindex); + stream_put(s, &nh->gate.ipv6, 16); + stream_putl(s, nh->ifindex); break; default: /* do nothing */ break; } + if (nh->nh_label) { + stream_putc(s, + nh->nh_label->num_labels); + if (nh->nh_label->num_labels) + stream_put( + s, + &nh->nh_label->label[0], + nh->nh_label->num_labels + * sizeof(mpls_label_t)); + } else + stream_putc(s, 0); num++; } stream_putc_at(s, nump, num);