mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 15:47:22 +00:00
Merge pull request #4496 from chiragshah6/evpn_dev2
bgpd: vrf route leak handle bgp instance delete recreate
This commit is contained in:
commit
53f477016e
@ -1614,11 +1614,13 @@ void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
|
|||||||
{
|
{
|
||||||
const char *export_name;
|
const char *export_name;
|
||||||
vpn_policy_direction_t idir, edir;
|
vpn_policy_direction_t idir, edir;
|
||||||
char *vname;
|
char *vname, *tmp_name;
|
||||||
char buf[1000];
|
char buf[RD_ADDRSTRLEN];
|
||||||
struct ecommunity *ecom;
|
struct ecommunity *ecom;
|
||||||
bool first_export = false;
|
bool first_export = false;
|
||||||
int debug;
|
int debug;
|
||||||
|
struct listnode *node;
|
||||||
|
bool is_inst_match = false;
|
||||||
|
|
||||||
export_name = to_bgp->name ? to_bgp->name : VRF_DEFAULT_NAME;
|
export_name = to_bgp->name ? to_bgp->name : VRF_DEFAULT_NAME;
|
||||||
idir = BGP_VPN_POLICY_DIR_FROMVPN;
|
idir = BGP_VPN_POLICY_DIR_FROMVPN;
|
||||||
@ -1634,13 +1636,41 @@ void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
|
|||||||
vname = (from_bgp->name ? XSTRDUP(MTYPE_TMP, from_bgp->name)
|
vname = (from_bgp->name ? XSTRDUP(MTYPE_TMP, from_bgp->name)
|
||||||
: XSTRDUP(MTYPE_TMP, VRF_DEFAULT_NAME));
|
: XSTRDUP(MTYPE_TMP, VRF_DEFAULT_NAME));
|
||||||
|
|
||||||
listnode_add(to_bgp->vpn_policy[afi].import_vrf, vname);
|
/* Check the import_vrf list of destination vrf for the source vrf name,
|
||||||
|
* insert otherwise.
|
||||||
|
*/
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi].import_vrf,
|
||||||
|
node, tmp_name)) {
|
||||||
|
if (strcmp(vname, tmp_name) == 0) {
|
||||||
|
is_inst_match = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!is_inst_match)
|
||||||
|
listnode_add(to_bgp->vpn_policy[afi].import_vrf,
|
||||||
|
vname);
|
||||||
|
|
||||||
if (!listcount(from_bgp->vpn_policy[afi].export_vrf))
|
/* Check if the source vrf already exports to any vrf,
|
||||||
first_export = true;
|
* first time export requires to setup auto derived RD/RT values.
|
||||||
|
* Add the destination vrf name to export vrf list if it is
|
||||||
|
* not present.
|
||||||
|
*/
|
||||||
|
is_inst_match = false;
|
||||||
vname = XSTRDUP(MTYPE_TMP, export_name);
|
vname = XSTRDUP(MTYPE_TMP, export_name);
|
||||||
listnode_add(from_bgp->vpn_policy[afi].export_vrf, vname);
|
if (!listcount(from_bgp->vpn_policy[afi].export_vrf)) {
|
||||||
|
first_export = true;
|
||||||
|
} else {
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(from_bgp->vpn_policy[afi].export_vrf,
|
||||||
|
node, tmp_name)) {
|
||||||
|
if (strcmp(vname, tmp_name) == 0) {
|
||||||
|
is_inst_match = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!is_inst_match)
|
||||||
|
listnode_add(from_bgp->vpn_policy[afi].export_vrf,
|
||||||
|
vname);
|
||||||
/* Update import RT for current VRF using export RT of the VRF we're
|
/* Update import RT for current VRF using export RT of the VRF we're
|
||||||
* importing from. First though, make sure "import_vrf" has that
|
* importing from. First though, make sure "import_vrf" has that
|
||||||
* set.
|
* set.
|
||||||
@ -1702,7 +1732,7 @@ void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
|
|||||||
const char *export_name, *tmp_name;
|
const char *export_name, *tmp_name;
|
||||||
vpn_policy_direction_t idir, edir;
|
vpn_policy_direction_t idir, edir;
|
||||||
char *vname;
|
char *vname;
|
||||||
struct ecommunity *ecom;
|
struct ecommunity *ecom = NULL;
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
int debug;
|
int debug;
|
||||||
|
|
||||||
@ -1747,10 +1777,12 @@ void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
|
|||||||
if (to_bgp->vpn_policy[afi].import_vrf->count == 0) {
|
if (to_bgp->vpn_policy[afi].import_vrf->count == 0) {
|
||||||
UNSET_FLAG(to_bgp->af_flags[afi][safi],
|
UNSET_FLAG(to_bgp->af_flags[afi][safi],
|
||||||
BGP_CONFIG_VRF_TO_VRF_IMPORT);
|
BGP_CONFIG_VRF_TO_VRF_IMPORT);
|
||||||
ecommunity_free(&to_bgp->vpn_policy[afi].rtlist[idir]);
|
if (to_bgp->vpn_policy[afi].rtlist[idir])
|
||||||
|
ecommunity_free(&to_bgp->vpn_policy[afi].rtlist[idir]);
|
||||||
} else {
|
} else {
|
||||||
ecom = from_bgp->vpn_policy[afi].rtlist[edir];
|
ecom = from_bgp->vpn_policy[afi].rtlist[edir];
|
||||||
ecommunity_del_val(to_bgp->vpn_policy[afi].rtlist[idir],
|
if (ecom)
|
||||||
|
ecommunity_del_val(to_bgp->vpn_policy[afi].rtlist[idir],
|
||||||
(struct ecommunity_val *)ecom->val);
|
(struct ecommunity_val *)ecom->val);
|
||||||
vpn_leak_postchange(idir, afi, bgp_get_default(), to_bgp);
|
vpn_leak_postchange(idir, afi, bgp_get_default(), to_bgp);
|
||||||
}
|
}
|
||||||
@ -1783,8 +1815,11 @@ void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
|
|||||||
*
|
*
|
||||||
* import_vrf and export_vrf must match in having
|
* import_vrf and export_vrf must match in having
|
||||||
* the in/out names as appropriate.
|
* the in/out names as appropriate.
|
||||||
|
* export_vrf list could have been cleaned up
|
||||||
|
* as part of no router bgp source instnace.
|
||||||
*/
|
*/
|
||||||
assert(vname);
|
if (!vname)
|
||||||
|
return;
|
||||||
|
|
||||||
listnode_delete(from_bgp->vpn_policy[afi].export_vrf, vname);
|
listnode_delete(from_bgp->vpn_policy[afi].export_vrf, vname);
|
||||||
XFREE(MTYPE_TMP, vname);
|
XFREE(MTYPE_TMP, vname);
|
||||||
@ -2471,3 +2506,167 @@ void vpn_leak_postchange_all(void)
|
|||||||
bgp);
|
bgp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* When a bgp vrf instance is unconfigured, remove its routes
|
||||||
|
* from the VPN table and this vrf could be importing routes from other
|
||||||
|
* bgp vrf instnaces, unimport them.
|
||||||
|
* VRF X and VRF Y are exporting routes to each other.
|
||||||
|
* When VRF X is deleted, unimport its routes from all target vrfs,
|
||||||
|
* also VRF Y should unimport its routes from VRF X table.
|
||||||
|
* This will ensure VPN table is cleaned up appropriately.
|
||||||
|
*/
|
||||||
|
int bgp_vpn_leak_unimport(struct bgp *from_bgp, struct vty *vty)
|
||||||
|
{
|
||||||
|
struct bgp *to_bgp;
|
||||||
|
const char *tmp_name;
|
||||||
|
char *vname;
|
||||||
|
struct listnode *node, *next;
|
||||||
|
safi_t safi = SAFI_UNICAST;
|
||||||
|
afi_t afi;
|
||||||
|
bool is_vrf_leak_bind;
|
||||||
|
int debug;
|
||||||
|
|
||||||
|
if (from_bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
|
||||||
|
BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
|
||||||
|
|
||||||
|
tmp_name = from_bgp->name ? from_bgp->name : VRF_DEFAULT_NAME;
|
||||||
|
|
||||||
|
for (afi = 0; afi < AFI_MAX; ++afi) {
|
||||||
|
/* vrf leak is for IPv4 and IPv6 Unicast only */
|
||||||
|
if (afi != AFI_IP && afi != AFI_IP6)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, to_bgp)) {
|
||||||
|
if (from_bgp == to_bgp)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Unimport and remove source vrf from the
|
||||||
|
* other vrfs import list.
|
||||||
|
*/
|
||||||
|
struct vpn_policy *to_vpolicy;
|
||||||
|
|
||||||
|
is_vrf_leak_bind = false;
|
||||||
|
to_vpolicy = &(to_bgp->vpn_policy[afi]);
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(to_vpolicy->import_vrf, node,
|
||||||
|
vname)) {
|
||||||
|
if (strcmp(vname, tmp_name) == 0) {
|
||||||
|
is_vrf_leak_bind = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* skip this bgp instance as there is no leak to this
|
||||||
|
* vrf instance.
|
||||||
|
*/
|
||||||
|
if (!is_vrf_leak_bind)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
zlog_debug("%s: unimport routes from %s to_bgp %s afi %s import vrfs count %u",
|
||||||
|
__func__, from_bgp->name_pretty,
|
||||||
|
to_bgp->name_pretty, afi2str(afi),
|
||||||
|
to_vpolicy->import_vrf->count);
|
||||||
|
|
||||||
|
vrf_unimport_from_vrf(to_bgp, from_bgp, afi, safi);
|
||||||
|
|
||||||
|
/* readd vrf name as unimport removes import vrf name
|
||||||
|
* from the destination vrf's import list where the
|
||||||
|
* `import vrf` configuration still exist.
|
||||||
|
*/
|
||||||
|
vname = XSTRDUP(MTYPE_TMP, tmp_name);
|
||||||
|
listnode_add(to_bgp->vpn_policy[afi].import_vrf,
|
||||||
|
vname);
|
||||||
|
SET_FLAG(to_bgp->af_flags[afi][safi],
|
||||||
|
BGP_CONFIG_VRF_TO_VRF_IMPORT);
|
||||||
|
|
||||||
|
/* If to_bgp exports its routes to the bgp vrf
|
||||||
|
* which is being deleted, un-import the
|
||||||
|
* to_bgp routes from VPN.
|
||||||
|
*/
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi]
|
||||||
|
.export_vrf, node,
|
||||||
|
vname)) {
|
||||||
|
if (strcmp(vname, tmp_name) == 0) {
|
||||||
|
vrf_unimport_from_vrf(from_bgp, to_bgp,
|
||||||
|
afi, safi);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When a router bgp is configured, there could be a bgp vrf
|
||||||
|
* instance importing routes from this newly configured
|
||||||
|
* bgp vrf instance. Export routes from configured
|
||||||
|
* bgp vrf to VPN.
|
||||||
|
* VRF Y has import from bgp vrf x,
|
||||||
|
* when a bgp vrf x instance is created, export its routes
|
||||||
|
* to VRF Y instance.
|
||||||
|
*/
|
||||||
|
void bgp_vpn_leak_export(struct bgp *from_bgp)
|
||||||
|
{
|
||||||
|
afi_t afi;
|
||||||
|
const char *export_name;
|
||||||
|
char *vname;
|
||||||
|
struct listnode *node, *next;
|
||||||
|
struct ecommunity *ecom;
|
||||||
|
vpn_policy_direction_t idir, edir;
|
||||||
|
safi_t safi = SAFI_UNICAST;
|
||||||
|
struct bgp *to_bgp;
|
||||||
|
int debug;
|
||||||
|
|
||||||
|
debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
|
||||||
|
BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
|
||||||
|
|
||||||
|
idir = BGP_VPN_POLICY_DIR_FROMVPN;
|
||||||
|
edir = BGP_VPN_POLICY_DIR_TOVPN;
|
||||||
|
|
||||||
|
export_name = (from_bgp->name ? XSTRDUP(MTYPE_TMP, from_bgp->name)
|
||||||
|
: XSTRDUP(MTYPE_TMP, VRF_DEFAULT_NAME));
|
||||||
|
|
||||||
|
for (afi = 0; afi < AFI_MAX; ++afi) {
|
||||||
|
/* vrf leak is for IPv4 and IPv6 Unicast only */
|
||||||
|
if (afi != AFI_IP && afi != AFI_IP6)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, to_bgp)) {
|
||||||
|
if (from_bgp == to_bgp)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* bgp instance has import list, check to see if newly
|
||||||
|
* configured bgp instance is the list.
|
||||||
|
*/
|
||||||
|
struct vpn_policy *to_vpolicy;
|
||||||
|
|
||||||
|
to_vpolicy = &(to_bgp->vpn_policy[afi]);
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(to_vpolicy->import_vrf,
|
||||||
|
node, vname)) {
|
||||||
|
if (strcmp(vname, export_name) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
zlog_debug("%s: found from_bgp %s in to_bgp %s import list, import routes.",
|
||||||
|
__func__,
|
||||||
|
export_name, to_bgp->name_pretty);
|
||||||
|
|
||||||
|
ecom = from_bgp->vpn_policy[afi].rtlist[edir];
|
||||||
|
/* remove import rt, it will be readded
|
||||||
|
* as part of import from vrf.
|
||||||
|
*/
|
||||||
|
if (ecom)
|
||||||
|
ecommunity_del_val(
|
||||||
|
to_vpolicy->rtlist[idir],
|
||||||
|
(struct ecommunity_val *)
|
||||||
|
ecom->val);
|
||||||
|
vrf_import_from_vrf(to_bgp, from_bgp,
|
||||||
|
afi, safi);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -266,5 +266,7 @@ extern vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey);
|
|||||||
extern void vpn_leak_postchange_all(void);
|
extern void vpn_leak_postchange_all(void);
|
||||||
extern void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw,
|
extern void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw,
|
||||||
bool is_config);
|
bool is_config);
|
||||||
|
extern int bgp_vpn_leak_unimport(struct bgp *from_bgp, struct vty *vty);
|
||||||
|
extern void bgp_vpn_leak_export(struct bgp *from_bgp);
|
||||||
|
|
||||||
#endif /* _QUAGGA_BGP_MPLSVPN_H */
|
#endif /* _QUAGGA_BGP_MPLSVPN_H */
|
||||||
|
@ -999,6 +999,8 @@ DEFUN_NOSH (router_bgp,
|
|||||||
if (is_new_bgp && inst_type == BGP_INSTANCE_TYPE_DEFAULT)
|
if (is_new_bgp && inst_type == BGP_INSTANCE_TYPE_DEFAULT)
|
||||||
vpn_leak_postchange_all();
|
vpn_leak_postchange_all();
|
||||||
|
|
||||||
|
if (inst_type == BGP_INSTANCE_TYPE_VRF)
|
||||||
|
bgp_vpn_leak_export(bgp);
|
||||||
/* Pending: handle when user tries to change a view to vrf n vv.
|
/* Pending: handle when user tries to change a view to vrf n vv.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
@ -1081,6 +1083,9 @@ DEFUN (no_router_bgp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bgp_vpn_leak_unimport(bgp, vty))
|
||||||
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
|
|
||||||
bgp_delete(bgp);
|
bgp_delete(bgp);
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
@ -11313,15 +11318,19 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
|
|||||||
json_object_array_add(json_import_vrfs,
|
json_object_array_add(json_import_vrfs,
|
||||||
json_object_new_string(vname));
|
json_object_new_string(vname));
|
||||||
|
|
||||||
|
json_object_object_add(json, "importFromVrfs",
|
||||||
|
json_import_vrfs);
|
||||||
dir = BGP_VPN_POLICY_DIR_FROMVPN;
|
dir = BGP_VPN_POLICY_DIR_FROMVPN;
|
||||||
ecom_str = ecommunity_ecom2str(
|
if (bgp->vpn_policy[afi].rtlist[dir]) {
|
||||||
|
ecom_str = ecommunity_ecom2str(
|
||||||
bgp->vpn_policy[afi].rtlist[dir],
|
bgp->vpn_policy[afi].rtlist[dir],
|
||||||
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
||||||
json_object_object_add(json, "importFromVrfs",
|
json_object_string_add(json, "importRts",
|
||||||
json_import_vrfs);
|
ecom_str);
|
||||||
json_object_string_add(json, "importRts", ecom_str);
|
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
||||||
|
} else
|
||||||
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
json_object_string_add(json, "importRts",
|
||||||
|
"none");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CHECK_FLAG(bgp->af_flags[afi][safi],
|
if (!CHECK_FLAG(bgp->af_flags[afi][safi],
|
||||||
@ -11345,12 +11354,16 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
|
|||||||
buf1, RD_ADDRSTRLEN));
|
buf1, RD_ADDRSTRLEN));
|
||||||
|
|
||||||
dir = BGP_VPN_POLICY_DIR_TOVPN;
|
dir = BGP_VPN_POLICY_DIR_TOVPN;
|
||||||
ecom_str = ecommunity_ecom2str(
|
if (bgp->vpn_policy[afi].rtlist[dir]) {
|
||||||
|
ecom_str = ecommunity_ecom2str(
|
||||||
bgp->vpn_policy[afi].rtlist[dir],
|
bgp->vpn_policy[afi].rtlist[dir],
|
||||||
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
||||||
json_object_string_add(json, "exportRts", ecom_str);
|
json_object_string_add(json, "exportRts",
|
||||||
|
ecom_str);
|
||||||
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
||||||
|
} else
|
||||||
|
json_object_string_add(json, "exportRts",
|
||||||
|
"none");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_json) {
|
if (use_json) {
|
||||||
@ -11383,12 +11396,16 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
|
|||||||
vty_out(vty, " %s\n", vname);
|
vty_out(vty, " %s\n", vname);
|
||||||
|
|
||||||
dir = BGP_VPN_POLICY_DIR_FROMVPN;
|
dir = BGP_VPN_POLICY_DIR_FROMVPN;
|
||||||
ecom_str = ecommunity_ecom2str(
|
ecom_str = NULL;
|
||||||
|
if (bgp->vpn_policy[afi].rtlist[dir]) {
|
||||||
|
ecom_str = ecommunity_ecom2str(
|
||||||
bgp->vpn_policy[afi].rtlist[dir],
|
bgp->vpn_policy[afi].rtlist[dir],
|
||||||
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
||||||
vty_out(vty, "Import RT(s): %s\n", ecom_str);
|
vty_out(vty, "Import RT(s): %s\n", ecom_str);
|
||||||
|
|
||||||
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
||||||
|
} else
|
||||||
|
vty_out(vty, "Import RT(s):\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CHECK_FLAG(bgp->af_flags[afi][safi],
|
if (!CHECK_FLAG(bgp->af_flags[afi][safi],
|
||||||
@ -11411,11 +11428,14 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
|
|||||||
buf1, RD_ADDRSTRLEN));
|
buf1, RD_ADDRSTRLEN));
|
||||||
|
|
||||||
dir = BGP_VPN_POLICY_DIR_TOVPN;
|
dir = BGP_VPN_POLICY_DIR_TOVPN;
|
||||||
ecom_str = ecommunity_ecom2str(
|
if (bgp->vpn_policy[afi].rtlist[dir]) {
|
||||||
|
ecom_str = ecommunity_ecom2str(
|
||||||
bgp->vpn_policy[afi].rtlist[dir],
|
bgp->vpn_policy[afi].rtlist[dir],
|
||||||
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
||||||
vty_out(vty, "Export RT: %s\n", ecom_str);
|
vty_out(vty, "Export RT: %s\n", ecom_str);
|
||||||
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
||||||
|
} else
|
||||||
|
vty_out(vty, "Import RT(s):\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user