forked from Mirror/frr
lib: convert if_zapi_callbacks into actual hooks
...so that multiple functions can be subscribed. The create/destroy hooks are renamed to real/unreal because that's what they *actually* signal. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
parent
8e3a96e846
commit
d889055d8e
|
@ -182,8 +182,10 @@ main(int argc, char **argv)
|
||||||
change_smoothing_half_life(BABEL_DEFAULT_SMOOTHING_HALF_LIFE);
|
change_smoothing_half_life(BABEL_DEFAULT_SMOOTHING_HALF_LIFE);
|
||||||
|
|
||||||
/* init some quagga's dependencies, and babeld's commands */
|
/* init some quagga's dependencies, and babeld's commands */
|
||||||
if_zapi_callbacks(babel_ifp_create, babel_ifp_up,
|
hook_register_prio(if_real, 0, babel_ifp_create);
|
||||||
babel_ifp_down, babel_ifp_destroy);
|
hook_register_prio(if_up, 0, babel_ifp_up);
|
||||||
|
hook_register_prio(if_down, 0, babel_ifp_down);
|
||||||
|
hook_register_prio(if_unreal, 0, babel_ifp_destroy);
|
||||||
babeld_quagga_init();
|
babeld_quagga_init();
|
||||||
/* init zebra client's structure and it's commands */
|
/* init zebra client's structure and it's commands */
|
||||||
/* this replace kernel_setup && kernel_setup_socket */
|
/* this replace kernel_setup && kernel_setup_socket */
|
||||||
|
|
|
@ -826,7 +826,8 @@ static zclient_handler *const bfd_handlers[] = {
|
||||||
|
|
||||||
void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
|
void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
|
||||||
{
|
{
|
||||||
if_zapi_callbacks(bfd_ifp_create, NULL, NULL, bfd_ifp_destroy);
|
hook_register_prio(if_real, 0, bfd_ifp_create);
|
||||||
|
hook_register_prio(if_unreal, 0, bfd_ifp_destroy);
|
||||||
zclient = zclient_new(master, &zclient_options_default, bfd_handlers,
|
zclient = zclient_new(master, &zclient_options_default, bfd_handlers,
|
||||||
array_size(bfd_handlers));
|
array_size(bfd_handlers));
|
||||||
assert(zclient != NULL);
|
assert(zclient != NULL);
|
||||||
|
|
|
@ -3442,8 +3442,10 @@ void bgp_zebra_init(struct event_loop *master, unsigned short instance)
|
||||||
options.synchronous = true;
|
options.synchronous = true;
|
||||||
zclient_num_connects = 0;
|
zclient_num_connects = 0;
|
||||||
|
|
||||||
if_zapi_callbacks(bgp_ifp_create, bgp_ifp_up,
|
hook_register_prio(if_real, 0, bgp_ifp_create);
|
||||||
bgp_ifp_down, bgp_ifp_destroy);
|
hook_register_prio(if_up, 0, bgp_ifp_up);
|
||||||
|
hook_register_prio(if_down, 0, bgp_ifp_down);
|
||||||
|
hook_register_prio(if_unreal, 0, bgp_ifp_destroy);
|
||||||
|
|
||||||
/* Set default values. */
|
/* Set default values. */
|
||||||
zclient = zclient_new(master, &zclient_options_default, bgp_handlers,
|
zclient = zclient_new(master, &zclient_options_default, bgp_handlers,
|
||||||
|
|
|
@ -202,8 +202,10 @@ struct list *eigrp_iflist;
|
||||||
|
|
||||||
void eigrp_if_init(void)
|
void eigrp_if_init(void)
|
||||||
{
|
{
|
||||||
if_zapi_callbacks(eigrp_ifp_create, eigrp_ifp_up,
|
hook_register_prio(if_real, 0, eigrp_ifp_create);
|
||||||
eigrp_ifp_down, eigrp_ifp_destroy);
|
hook_register_prio(if_up, 0, eigrp_ifp_up);
|
||||||
|
hook_register_prio(if_down, 0, eigrp_ifp_down);
|
||||||
|
hook_register_prio(if_unreal, 0, eigrp_ifp_destroy);
|
||||||
/* Initialize Zebra interface data structure. */
|
/* Initialize Zebra interface data structure. */
|
||||||
// hook_register_prio(if_add, 0, eigrp_if_new);
|
// hook_register_prio(if_add, 0, eigrp_if_new);
|
||||||
hook_register_prio(if_del, 0, eigrp_if_delete_hook);
|
hook_register_prio(if_del, 0, eigrp_if_delete_hook);
|
||||||
|
|
|
@ -1680,6 +1680,8 @@ void isis_circuit_init(void)
|
||||||
#else
|
#else
|
||||||
if_cmd_init_default();
|
if_cmd_init_default();
|
||||||
#endif
|
#endif
|
||||||
if_zapi_callbacks(isis_ifp_create, isis_ifp_up,
|
hook_register_prio(if_real, 0, isis_ifp_create);
|
||||||
isis_ifp_down, isis_ifp_destroy);
|
hook_register_prio(if_up, 0, isis_ifp_up);
|
||||||
|
hook_register_prio(if_down, 0, isis_ifp_down);
|
||||||
|
hook_register_prio(if_unreal, 0, isis_ifp_destroy);
|
||||||
}
|
}
|
||||||
|
|
|
@ -682,7 +682,10 @@ static zclient_handler *const ldp_handlers[] = {
|
||||||
|
|
||||||
void ldp_zebra_init(struct event_loop *master)
|
void ldp_zebra_init(struct event_loop *master)
|
||||||
{
|
{
|
||||||
if_zapi_callbacks(ldp_ifp_create, ldp_ifp_up, ldp_ifp_down, ldp_ifp_destroy);
|
hook_register_prio(if_real, 0, ldp_ifp_create);
|
||||||
|
hook_register_prio(if_up, 0, ldp_ifp_up);
|
||||||
|
hook_register_prio(if_down, 0, ldp_ifp_down);
|
||||||
|
hook_register_prio(if_unreal, 0, ldp_ifp_destroy);
|
||||||
|
|
||||||
/* Set default values. */
|
/* Set default values. */
|
||||||
zclient = zclient_new(master, &zclient_options_default, ldp_handlers,
|
zclient = zclient_new(master, &zclient_options_default, ldp_handlers,
|
||||||
|
|
38
lib/if.c
38
lib/if.c
|
@ -42,15 +42,14 @@ RB_GENERATE(if_index_head, interface, index_entry, if_cmp_index_func);
|
||||||
|
|
||||||
DEFINE_QOBJ_TYPE(interface);
|
DEFINE_QOBJ_TYPE(interface);
|
||||||
|
|
||||||
DEFINE_HOOK(if_add, (struct interface * ifp), (ifp));
|
DEFINE_HOOK(if_add, (struct interface *ifp), (ifp));
|
||||||
DEFINE_KOOH(if_del, (struct interface * ifp), (ifp));
|
DEFINE_KOOH(if_del, (struct interface *ifp), (ifp));
|
||||||
|
|
||||||
static struct interface_master{
|
DEFINE_HOOK(if_real, (struct interface *ifp), (ifp));
|
||||||
int (*create_hook)(struct interface *ifp);
|
DEFINE_KOOH(if_unreal, (struct interface *ifp), (ifp));
|
||||||
int (*up_hook)(struct interface *ifp);
|
|
||||||
int (*down_hook)(struct interface *ifp);
|
DEFINE_HOOK(if_up, (struct interface *ifp), (ifp));
|
||||||
int (*destroy_hook)(struct interface *ifp);
|
DEFINE_KOOH(if_down, (struct interface *ifp), (ifp));
|
||||||
} ifp_master = { 0, };
|
|
||||||
|
|
||||||
/* Compare interface names, returning an integer greater than, equal to, or
|
/* Compare interface names, returning an integer greater than, equal to, or
|
||||||
* less than 0, (following the strcmp convention), according to the
|
* less than 0, (following the strcmp convention), according to the
|
||||||
|
@ -180,14 +179,12 @@ static struct interface *if_new(struct vrf *vrf)
|
||||||
|
|
||||||
void if_new_via_zapi(struct interface *ifp)
|
void if_new_via_zapi(struct interface *ifp)
|
||||||
{
|
{
|
||||||
if (ifp_master.create_hook)
|
hook_call(if_real, ifp);
|
||||||
(*ifp_master.create_hook)(ifp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_destroy_via_zapi(struct interface *ifp)
|
void if_destroy_via_zapi(struct interface *ifp)
|
||||||
{
|
{
|
||||||
if (ifp_master.destroy_hook)
|
hook_call(if_unreal, ifp);
|
||||||
(*ifp_master.destroy_hook)(ifp);
|
|
||||||
|
|
||||||
ifp->oldifindex = ifp->ifindex;
|
ifp->oldifindex = ifp->ifindex;
|
||||||
if_set_index(ifp, IFINDEX_INTERNAL);
|
if_set_index(ifp, IFINDEX_INTERNAL);
|
||||||
|
@ -198,14 +195,12 @@ void if_destroy_via_zapi(struct interface *ifp)
|
||||||
|
|
||||||
void if_up_via_zapi(struct interface *ifp)
|
void if_up_via_zapi(struct interface *ifp)
|
||||||
{
|
{
|
||||||
if (ifp_master.up_hook)
|
hook_call(if_up, ifp);
|
||||||
(*ifp_master.up_hook)(ifp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_down_via_zapi(struct interface *ifp)
|
void if_down_via_zapi(struct interface *ifp)
|
||||||
{
|
{
|
||||||
if (ifp_master.down_hook)
|
hook_call(if_down, ifp);
|
||||||
(*ifp_master.down_hook)(ifp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct interface *if_create_name(const char *name, struct vrf *vrf)
|
static struct interface *if_create_name(const char *name, struct vrf *vrf)
|
||||||
|
@ -1477,17 +1472,6 @@ void if_cmd_init_default(void)
|
||||||
if_cmd_init(if_nb_config_write);
|
if_cmd_init(if_nb_config_write);
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_zapi_callbacks(int (*create)(struct interface *ifp),
|
|
||||||
int (*up)(struct interface *ifp),
|
|
||||||
int (*down)(struct interface *ifp),
|
|
||||||
int (*destroy)(struct interface *ifp))
|
|
||||||
{
|
|
||||||
ifp_master.create_hook = create;
|
|
||||||
ifp_master.up_hook = up;
|
|
||||||
ifp_master.down_hook = down;
|
|
||||||
ifp_master.destroy_hook = destroy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------- Northbound callbacks ------- */
|
/* ------- Northbound callbacks ------- */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
27
lib/if.h
27
lib/if.h
|
@ -386,8 +386,27 @@ DECLARE_QOBJ_TYPE(interface);
|
||||||
* can use 1000+ so they run after the daemon has initialised daemon-specific
|
* can use 1000+ so they run after the daemon has initialised daemon-specific
|
||||||
* interface data
|
* interface data
|
||||||
*/
|
*/
|
||||||
DECLARE_HOOK(if_add, (struct interface * ifp), (ifp));
|
DECLARE_HOOK(if_add, (struct interface *ifp), (ifp));
|
||||||
DECLARE_KOOH(if_del, (struct interface * ifp), (ifp));
|
DECLARE_KOOH(if_del, (struct interface *ifp), (ifp));
|
||||||
|
|
||||||
|
/* called (in daemons) when ZAPI tells us the interface actually exists
|
||||||
|
* (ifindex != IFINDEX_INTERNAL)
|
||||||
|
*
|
||||||
|
* WARNING: these 2 hooks NEVER CALLED inside zebra!
|
||||||
|
*/
|
||||||
|
DECLARE_HOOK(if_real, (struct interface *ifp), (ifp));
|
||||||
|
DECLARE_KOOH(if_unreal, (struct interface *ifp), (ifp));
|
||||||
|
|
||||||
|
/* called (in daemons) on state changes on interfaces. Whether this is admin
|
||||||
|
* state (= pure config) or carrier state (= hardware link plugged) depends on
|
||||||
|
* zebra's "link-detect" configuration. By default, it's carrier state, so
|
||||||
|
* this won't happen until the interface actually has a link.
|
||||||
|
*
|
||||||
|
* WARNING: these 2 hooks NEVER CALLED inside zebra!
|
||||||
|
*/
|
||||||
|
DECLARE_HOOK(if_up, (struct interface *ifp), (ifp));
|
||||||
|
DECLARE_KOOH(if_down, (struct interface *ifp), (ifp));
|
||||||
|
|
||||||
|
|
||||||
#define METRIC_MAX (~0)
|
#define METRIC_MAX (~0)
|
||||||
|
|
||||||
|
@ -609,10 +628,6 @@ extern void if_vty_config_start(struct vty *vty, struct interface *ifp);
|
||||||
extern void if_vty_config_end(struct vty *vty);
|
extern void if_vty_config_end(struct vty *vty);
|
||||||
extern void if_cmd_init(int (*config_write)(struct vty *));
|
extern void if_cmd_init(int (*config_write)(struct vty *));
|
||||||
extern void if_cmd_init_default(void);
|
extern void if_cmd_init_default(void);
|
||||||
extern void if_zapi_callbacks(int (*create)(struct interface *ifp),
|
|
||||||
int (*up)(struct interface *ifp),
|
|
||||||
int (*down)(struct interface *ifp),
|
|
||||||
int (*destroy)(struct interface *ifp));
|
|
||||||
|
|
||||||
extern void if_new_via_zapi(struct interface *ifp);
|
extern void if_new_via_zapi(struct interface *ifp);
|
||||||
extern void if_up_via_zapi(struct interface *ifp);
|
extern void if_up_via_zapi(struct interface *ifp);
|
||||||
|
|
|
@ -155,8 +155,10 @@ int main(int argc, char **argv)
|
||||||
nhrp_vc_init();
|
nhrp_vc_init();
|
||||||
nhrp_packet_init();
|
nhrp_packet_init();
|
||||||
vici_init();
|
vici_init();
|
||||||
if_zapi_callbacks(nhrp_ifp_create, nhrp_ifp_up,
|
hook_register_prio(if_real, 0, nhrp_ifp_create);
|
||||||
nhrp_ifp_down, nhrp_ifp_destroy);
|
hook_register_prio(if_up, 0, nhrp_ifp_up);
|
||||||
|
hook_register_prio(if_down, 0, nhrp_ifp_down);
|
||||||
|
hook_register_prio(if_unreal, 0, nhrp_ifp_destroy);
|
||||||
nhrp_zebra_init();
|
nhrp_zebra_init();
|
||||||
nhrp_shortcut_init();
|
nhrp_shortcut_init();
|
||||||
|
|
||||||
|
|
|
@ -2797,8 +2797,10 @@ void ospf6_interface_init(void)
|
||||||
{
|
{
|
||||||
/* Install interface node. */
|
/* Install interface node. */
|
||||||
if_cmd_init(config_write_interface);
|
if_cmd_init(config_write_interface);
|
||||||
if_zapi_callbacks(ospf6_ifp_create, ospf6_ifp_up, ospf6_ifp_down,
|
hook_register_prio(if_real, 0, ospf6_ifp_create);
|
||||||
ospf6_ifp_destroy);
|
hook_register_prio(if_up, 0, ospf6_ifp_up);
|
||||||
|
hook_register_prio(if_down, 0, ospf6_ifp_down);
|
||||||
|
hook_register_prio(if_unreal, 0, ospf6_ifp_destroy);
|
||||||
|
|
||||||
install_element(VIEW_NODE, &show_ipv6_ospf6_interface_prefix_cmd);
|
install_element(VIEW_NODE, &show_ipv6_ospf6_interface_prefix_cmd);
|
||||||
install_element(VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd);
|
install_element(VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd);
|
||||||
|
|
|
@ -1562,8 +1562,10 @@ void ospf_reset_hello_timer(struct interface *ifp, struct in_addr addr,
|
||||||
|
|
||||||
void ospf_if_init(void)
|
void ospf_if_init(void)
|
||||||
{
|
{
|
||||||
if_zapi_callbacks(ospf_ifp_create, ospf_ifp_up,
|
hook_register_prio(if_real, 0, ospf_ifp_create);
|
||||||
ospf_ifp_down, ospf_ifp_destroy);
|
hook_register_prio(if_up, 0, ospf_ifp_up);
|
||||||
|
hook_register_prio(if_down, 0, ospf_ifp_down);
|
||||||
|
hook_register_prio(if_unreal, 0, ospf_ifp_destroy);
|
||||||
|
|
||||||
/* Initialize Zebra interface data structure. */
|
/* Initialize Zebra interface data structure. */
|
||||||
hook_register_prio(if_add, 0, ospf_if_new_hook);
|
hook_register_prio(if_add, 0, ospf_if_new_hook);
|
||||||
|
|
|
@ -158,8 +158,10 @@ int main(int argc, char **argv, char **envp)
|
||||||
access_list_init();
|
access_list_init();
|
||||||
pbr_nht_init();
|
pbr_nht_init();
|
||||||
pbr_map_init();
|
pbr_map_init();
|
||||||
if_zapi_callbacks(pbr_ifp_create, pbr_ifp_up,
|
hook_register_prio(if_real, 0, pbr_ifp_create);
|
||||||
pbr_ifp_down, pbr_ifp_destroy);
|
hook_register_prio(if_up, 0, pbr_ifp_up);
|
||||||
|
hook_register_prio(if_down, 0, pbr_ifp_down);
|
||||||
|
hook_register_prio(if_unreal, 0, pbr_ifp_destroy);
|
||||||
pbr_zebra_init();
|
pbr_zebra_init();
|
||||||
pbr_vrf_init();
|
pbr_vrf_init();
|
||||||
pbr_vty_init();
|
pbr_vty_init();
|
||||||
|
|
|
@ -1771,8 +1771,10 @@ void pim_iface_init(void)
|
||||||
hook_register_prio(if_add, 0, pim_if_new_hook);
|
hook_register_prio(if_add, 0, pim_if_new_hook);
|
||||||
hook_register_prio(if_del, 0, pim_if_delete_hook);
|
hook_register_prio(if_del, 0, pim_if_delete_hook);
|
||||||
|
|
||||||
if_zapi_callbacks(pim_ifp_create, pim_ifp_up, pim_ifp_down,
|
hook_register_prio(if_real, 0, pim_ifp_create);
|
||||||
pim_ifp_destroy);
|
hook_register_prio(if_up, 0, pim_ifp_up);
|
||||||
|
hook_register_prio(if_down, 0, pim_ifp_down);
|
||||||
|
hook_register_prio(if_unreal, 0, pim_ifp_destroy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pim_if_membership_clear(struct interface *ifp)
|
static void pim_if_membership_clear(struct interface *ifp)
|
||||||
|
|
|
@ -1118,6 +1118,8 @@ void rip_if_init(void)
|
||||||
|
|
||||||
/* Install interface node. */
|
/* Install interface node. */
|
||||||
if_cmd_init_default();
|
if_cmd_init_default();
|
||||||
if_zapi_callbacks(rip_ifp_create, rip_ifp_up,
|
hook_register_prio(if_real, 0, rip_ifp_create);
|
||||||
rip_ifp_down, rip_ifp_destroy);
|
hook_register_prio(if_up, 0, rip_ifp_up);
|
||||||
|
hook_register_prio(if_down, 0, rip_ifp_down);
|
||||||
|
hook_register_prio(if_unreal, 0, rip_ifp_destroy);
|
||||||
}
|
}
|
||||||
|
|
|
@ -877,6 +877,8 @@ void ripng_if_init(void)
|
||||||
|
|
||||||
/* Install interface node. */
|
/* Install interface node. */
|
||||||
if_cmd_init_default();
|
if_cmd_init_default();
|
||||||
if_zapi_callbacks(ripng_ifp_create, ripng_ifp_up,
|
hook_register_prio(if_real, 0, ripng_ifp_create);
|
||||||
ripng_ifp_down, ripng_ifp_destroy);
|
hook_register_prio(if_up, 0, ripng_ifp_up);
|
||||||
|
hook_register_prio(if_down, 0, ripng_ifp_down);
|
||||||
|
hook_register_prio(if_unreal, 0, ripng_ifp_destroy);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1077,8 +1077,10 @@ void sharp_zebra_init(void)
|
||||||
{
|
{
|
||||||
struct zclient_options opt = {.receive_notify = true};
|
struct zclient_options opt = {.receive_notify = true};
|
||||||
|
|
||||||
if_zapi_callbacks(sharp_ifp_create, sharp_ifp_up, sharp_ifp_down,
|
hook_register_prio(if_real, 0, sharp_ifp_create);
|
||||||
sharp_ifp_destroy);
|
hook_register_prio(if_up, 0, sharp_ifp_up);
|
||||||
|
hook_register_prio(if_down, 0, sharp_ifp_down);
|
||||||
|
hook_register_prio(if_unreal, 0, sharp_ifp_destroy);
|
||||||
|
|
||||||
zclient = zclient_new(master, &opt, sharp_handlers,
|
zclient = zclient_new(master, &opt, sharp_handlers,
|
||||||
array_size(sharp_handlers));
|
array_size(sharp_handlers));
|
||||||
|
|
|
@ -542,8 +542,10 @@ void static_zebra_init(void)
|
||||||
{
|
{
|
||||||
struct zclient_options opt = { .receive_notify = true };
|
struct zclient_options opt = { .receive_notify = true };
|
||||||
|
|
||||||
if_zapi_callbacks(static_ifp_create, static_ifp_up,
|
hook_register_prio(if_real, 0, static_ifp_create);
|
||||||
static_ifp_down, static_ifp_destroy);
|
hook_register_prio(if_up, 0, static_ifp_up);
|
||||||
|
hook_register_prio(if_down, 0, static_ifp_down);
|
||||||
|
hook_register_prio(if_unreal, 0, static_ifp_destroy);
|
||||||
|
|
||||||
zclient = zclient_new(master, &opt, static_handlers,
|
zclient = zclient_new(master, &opt, static_handlers,
|
||||||
array_size(static_handlers));
|
array_size(static_handlers));
|
||||||
|
|
|
@ -183,8 +183,10 @@ static zclient_handler *const vrrp_handlers[] = {
|
||||||
|
|
||||||
void vrrp_zebra_init(void)
|
void vrrp_zebra_init(void)
|
||||||
{
|
{
|
||||||
if_zapi_callbacks(vrrp_ifp_create, vrrp_ifp_up,
|
hook_register_prio(if_real, 0, vrrp_ifp_create);
|
||||||
vrrp_ifp_down, vrrp_ifp_destroy);
|
hook_register_prio(if_up, 0, vrrp_ifp_up);
|
||||||
|
hook_register_prio(if_down, 0, vrrp_ifp_down);
|
||||||
|
hook_register_prio(if_unreal, 0, vrrp_ifp_destroy);
|
||||||
|
|
||||||
/* Socket for receiving updates from Zebra daemon */
|
/* Socket for receiving updates from Zebra daemon */
|
||||||
zclient = zclient_new(master, &zclient_options_default, vrrp_handlers,
|
zclient = zclient_new(master, &zclient_options_default, vrrp_handlers,
|
||||||
|
|
|
@ -5664,11 +5664,6 @@ void zebra_if_init(void)
|
||||||
/* Install configuration write function. */
|
/* Install configuration write function. */
|
||||||
if_cmd_init(if_config_write);
|
if_cmd_init(if_config_write);
|
||||||
install_node(&link_params_node);
|
install_node(&link_params_node);
|
||||||
/*
|
|
||||||
* This is *intentionally* setting this to NULL, signaling
|
|
||||||
* that interface creation for zebra acts differently
|
|
||||||
*/
|
|
||||||
if_zapi_callbacks(NULL, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
install_element(VIEW_NODE, &show_interface_cmd);
|
install_element(VIEW_NODE, &show_interface_cmd);
|
||||||
install_element(VIEW_NODE, &show_interface_vrf_all_cmd);
|
install_element(VIEW_NODE, &show_interface_vrf_all_cmd);
|
||||||
|
|
Loading…
Reference in a new issue