core: set route metrics earlier
Instead of creating most routes with metric 0 and then fixing them just before applying them, create the routes with the correct metric in the first place (so that NMIP4Config and NMIP6Config don't have to try to guess whether "metric 0" means "unset" or "actually metric 0").
This commit is contained in:
@@ -2483,6 +2483,7 @@ aipd_get_ip4_config (NMDevice *self, guint32 lla)
|
||||
route.network = htonl (0xE0000000L);
|
||||
route.plen = 4;
|
||||
route.source = NM_PLATFORM_SOURCE_IP4LL;
|
||||
route.metric = nm_device_get_priority (self);
|
||||
nm_ip4_config_add_route (config, &route);
|
||||
|
||||
return config;
|
||||
@@ -2885,6 +2886,7 @@ dhcp4_start (NMDevice *self,
|
||||
nm_device_get_ip_iface (self),
|
||||
tmp,
|
||||
nm_connection_get_uuid (connection),
|
||||
nm_device_get_priority (self),
|
||||
s_ip4,
|
||||
priv->dhcp_timeout,
|
||||
priv->dhcp_anycast_address);
|
||||
@@ -3325,6 +3327,7 @@ dhcp6_start (NMDevice *self,
|
||||
nm_device_get_ip_iface (self),
|
||||
tmp,
|
||||
nm_connection_get_uuid (connection),
|
||||
nm_device_get_priority (self),
|
||||
nm_connection_get_setting_ip6_config (connection),
|
||||
priv->dhcp_timeout,
|
||||
priv->dhcp_anycast_address,
|
||||
@@ -3623,6 +3626,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device
|
||||
route.plen = discovered_route->plen;
|
||||
route.gateway = discovered_route->gateway;
|
||||
route.source = NM_PLATFORM_SOURCE_RDISC;
|
||||
route.metric = nm_device_get_priority (device);
|
||||
|
||||
nm_ip6_config_add_route (priv->ac_ip6_config, &route);
|
||||
}
|
||||
@@ -5279,7 +5283,7 @@ nm_device_set_ip4_config (NMDevice *self,
|
||||
|
||||
/* Always commit to nm-platform to update lifetimes */
|
||||
if (commit && new_config) {
|
||||
success = nm_ip4_config_commit (new_config, ip_ifindex, nm_device_get_priority (self));
|
||||
success = nm_ip4_config_commit (new_config, ip_ifindex);
|
||||
if (!success)
|
||||
reason_local = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
|
||||
}
|
||||
@@ -5387,7 +5391,7 @@ nm_device_set_ip6_config (NMDevice *self,
|
||||
|
||||
/* Always commit to nm-platform to update lifetimes */
|
||||
if (commit && new_config) {
|
||||
success = nm_ip6_config_commit (new_config, ip_ifindex, nm_device_get_priority (self));
|
||||
success = nm_ip6_config_commit (new_config, ip_ifindex);
|
||||
if (!success)
|
||||
reason_local = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
|
||||
}
|
||||
|
@@ -39,6 +39,7 @@ typedef struct {
|
||||
GByteArray * hwaddr;
|
||||
gboolean ipv6;
|
||||
char * uuid;
|
||||
guint priority;
|
||||
guint32 timeout;
|
||||
GByteArray * duid;
|
||||
|
||||
@@ -72,6 +73,7 @@ enum {
|
||||
PROP_HWADDR,
|
||||
PROP_IPV6,
|
||||
PROP_UUID,
|
||||
PROP_PRIORITY,
|
||||
PROP_TIMEOUT,
|
||||
LAST_PROP
|
||||
};
|
||||
@@ -795,10 +797,12 @@ nm_dhcp_client_foreach_option (NMDHCPClient *self,
|
||||
/********************************************/
|
||||
|
||||
static gboolean
|
||||
ip4_process_dhcpcd_rfc3442_routes (const char *str,
|
||||
ip4_process_dhcpcd_rfc3442_routes (NMDHCPClient *self,
|
||||
const char *str,
|
||||
NMIP4Config *ip4_config,
|
||||
guint32 *gwaddr)
|
||||
{
|
||||
NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
|
||||
char **routes, **r;
|
||||
gboolean have_routes = FALSE;
|
||||
|
||||
@@ -847,6 +851,7 @@ ip4_process_dhcpcd_rfc3442_routes (const char *str,
|
||||
route.plen = rt_cidr;
|
||||
route.gateway = rt_route;
|
||||
route.source = NM_PLATFORM_SOURCE_DHCP;
|
||||
route.metric = priv->priority;
|
||||
nm_ip4_config_add_route (ip4_config, &route);
|
||||
}
|
||||
}
|
||||
@@ -918,10 +923,12 @@ error:
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_process_dhclient_rfc3442_routes (const char *str,
|
||||
ip4_process_dhclient_rfc3442_routes (NMDHCPClient *self,
|
||||
const char *str,
|
||||
NMIP4Config *ip4_config,
|
||||
guint32 *gwaddr)
|
||||
{
|
||||
NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
|
||||
char **octets, **o;
|
||||
gboolean have_routes = FALSE;
|
||||
NMPlatformIP4Route route;
|
||||
@@ -950,6 +957,7 @@ ip4_process_dhclient_rfc3442_routes (const char *str,
|
||||
|
||||
/* normal route */
|
||||
route.source = NM_PLATFORM_SOURCE_DHCP;
|
||||
route.metric = priv->priority;
|
||||
nm_ip4_config_add_route (ip4_config, &route);
|
||||
|
||||
nm_log_info (LOGD_DHCP4, " classless static route %s/%d gw %s",
|
||||
@@ -964,7 +972,8 @@ out:
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_process_classless_routes (GHashTable *options,
|
||||
ip4_process_classless_routes (NMDHCPClient *self,
|
||||
GHashTable *options,
|
||||
NMIP4Config *ip4_config,
|
||||
guint32 *gwaddr)
|
||||
{
|
||||
@@ -1020,15 +1029,16 @@ ip4_process_classless_routes (GHashTable *options,
|
||||
|
||||
if (strchr (str, '/')) {
|
||||
/* dhcpcd format */
|
||||
return ip4_process_dhcpcd_rfc3442_routes (str, ip4_config, gwaddr);
|
||||
return ip4_process_dhcpcd_rfc3442_routes (self, str, ip4_config, gwaddr);
|
||||
}
|
||||
|
||||
return ip4_process_dhclient_rfc3442_routes (str, ip4_config, gwaddr);
|
||||
return ip4_process_dhclient_rfc3442_routes (self, str, ip4_config, gwaddr);
|
||||
}
|
||||
|
||||
static void
|
||||
process_classful_routes (GHashTable *options, NMIP4Config *ip4_config)
|
||||
process_classful_routes (NMDHCPClient *self, GHashTable *options, NMIP4Config *ip4_config)
|
||||
{
|
||||
NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
|
||||
const char *str;
|
||||
char **searches, **s;
|
||||
|
||||
@@ -1070,6 +1080,7 @@ process_classful_routes (GHashTable *options, NMIP4Config *ip4_config)
|
||||
}
|
||||
route.gateway = rt_route;
|
||||
route.source = NM_PLATFORM_SOURCE_DHCP;
|
||||
route.metric = priv->priority;
|
||||
|
||||
nm_ip4_config_add_route (ip4_config, &route);
|
||||
nm_log_info (LOGD_DHCP, " static route %s",
|
||||
@@ -1166,8 +1177,8 @@ ip4_options_to_config (NMDHCPClient *self)
|
||||
/* Routes: if the server returns classless static routes, we MUST ignore
|
||||
* the 'static_routes' option.
|
||||
*/
|
||||
if (!ip4_process_classless_routes (priv->options, ip4_config, &gwaddr))
|
||||
process_classful_routes (priv->options, ip4_config);
|
||||
if (!ip4_process_classless_routes (self, priv->options, ip4_config, &gwaddr))
|
||||
process_classful_routes (self, priv->options, ip4_config);
|
||||
|
||||
if (gwaddr) {
|
||||
nm_log_info (LOGD_DHCP4, " gateway %s", nm_utils_inet4_ntop (gwaddr, NULL));
|
||||
@@ -1220,6 +1231,8 @@ ip4_options_to_config (NMDHCPClient *self)
|
||||
route.plen = 32;
|
||||
/* this will be a device route if gwaddr is 0 */
|
||||
route.gateway = gwaddr;
|
||||
route.source = NM_PLATFORM_SOURCE_DHCP;
|
||||
route.metric = priv->priority;
|
||||
nm_ip4_config_add_route (ip4_config, &route);
|
||||
nm_log_dbg (LOGD_IP, "adding route for server identifier: %s",
|
||||
nm_platform_ip4_route_to_string (&route));
|
||||
@@ -1499,6 +1512,9 @@ get_property (GObject *object, guint prop_id,
|
||||
case PROP_UUID:
|
||||
g_value_set_string (value, priv->uuid);
|
||||
break;
|
||||
case PROP_PRIORITY:
|
||||
g_value_set_uint (value, priv->priority);
|
||||
break;
|
||||
case PROP_TIMEOUT:
|
||||
g_value_set_uint (value, priv->timeout);
|
||||
break;
|
||||
@@ -1531,6 +1547,10 @@ set_property (GObject *object, guint prop_id,
|
||||
/* construct-only */
|
||||
priv->uuid = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_PRIORITY:
|
||||
/* construct-only */
|
||||
priv->priority = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_TIMEOUT:
|
||||
priv->timeout = g_value_get_uint (value);
|
||||
break;
|
||||
@@ -1622,6 +1642,14 @@ nm_dhcp_client_class_init (NMDHCPClientClass *client_class)
|
||||
NULL,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_PRIORITY,
|
||||
g_param_spec_uint (NM_DHCP_CLIENT_PRIORITY,
|
||||
"priority",
|
||||
"Priority",
|
||||
0, G_MAXUINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_TIMEOUT,
|
||||
g_param_spec_uint (NM_DHCP_CLIENT_TIMEOUT,
|
||||
|
@@ -38,6 +38,7 @@
|
||||
#define NM_DHCP_CLIENT_HWADDR "hwaddr"
|
||||
#define NM_DHCP_CLIENT_IPV6 "ipv6"
|
||||
#define NM_DHCP_CLIENT_UUID "uuid"
|
||||
#define NM_DHCP_CLIENT_PRIORITY "priority"
|
||||
#define NM_DHCP_CLIENT_TIMEOUT "timeout"
|
||||
|
||||
#define NM_DHCP_CLIENT_SIGNAL_TIMEOUT "timeout"
|
||||
|
@@ -384,6 +384,7 @@ client_start (NMDHCPManager *self,
|
||||
const char *iface,
|
||||
const GByteArray *hwaddr,
|
||||
const char *uuid,
|
||||
guint priority,
|
||||
gboolean ipv6,
|
||||
const char *dhcp_client_id,
|
||||
guint32 timeout,
|
||||
@@ -418,6 +419,7 @@ client_start (NMDHCPManager *self,
|
||||
NM_DHCP_CLIENT_HWADDR, hwaddr,
|
||||
NM_DHCP_CLIENT_IPV6, ipv6,
|
||||
NM_DHCP_CLIENT_UUID, uuid,
|
||||
NM_DHCP_CLIENT_PRIORITY, priority,
|
||||
NM_DHCP_CLIENT_TIMEOUT, timeout ? timeout : DHCP_TIMEOUT,
|
||||
NULL);
|
||||
g_return_val_if_fail (client != NULL, NULL);
|
||||
@@ -452,6 +454,7 @@ nm_dhcp_manager_start_ip4 (NMDHCPManager *self,
|
||||
const char *iface,
|
||||
const GByteArray *hwaddr,
|
||||
const char *uuid,
|
||||
guint priority,
|
||||
NMSettingIP4Config *s_ip4,
|
||||
guint32 timeout,
|
||||
GByteArray *dhcp_anycast_addr)
|
||||
@@ -469,7 +472,9 @@ nm_dhcp_manager_start_ip4 (NMDHCPManager *self,
|
||||
if (send_hostname)
|
||||
hostname = get_send_hostname (self, nm_setting_ip4_config_get_dhcp_hostname (s_ip4));
|
||||
|
||||
return client_start (self, iface, hwaddr, uuid, FALSE, nm_setting_ip4_config_get_dhcp_client_id (s_ip4), timeout, dhcp_anycast_addr, hostname, FALSE);
|
||||
return client_start (self, iface, hwaddr, uuid, priority, FALSE,
|
||||
nm_setting_ip4_config_get_dhcp_client_id (s_ip4),
|
||||
timeout, dhcp_anycast_addr, hostname, FALSE);
|
||||
}
|
||||
|
||||
/* Caller owns a reference to the NMDHCPClient on return */
|
||||
@@ -478,6 +483,7 @@ nm_dhcp_manager_start_ip6 (NMDHCPManager *self,
|
||||
const char *iface,
|
||||
const GByteArray *hwaddr,
|
||||
const char *uuid,
|
||||
guint priority,
|
||||
NMSettingIP6Config *s_ip6,
|
||||
guint32 timeout,
|
||||
GByteArray *dhcp_anycast_addr,
|
||||
@@ -489,7 +495,8 @@ nm_dhcp_manager_start_ip6 (NMDHCPManager *self,
|
||||
|
||||
hostname = get_send_hostname (self, nm_setting_ip6_config_get_dhcp_hostname (s_ip6));
|
||||
|
||||
return client_start (self, iface, hwaddr, uuid, TRUE, NULL, timeout, dhcp_anycast_addr, hostname, info_only);
|
||||
return client_start (self, iface, hwaddr, uuid, priority, TRUE,
|
||||
NULL, timeout, dhcp_anycast_addr, hostname, info_only);
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -68,6 +68,7 @@ NMDHCPClient * nm_dhcp_manager_start_ip4 (NMDHCPManager *manager,
|
||||
const char *iface,
|
||||
const GByteArray *hwaddr,
|
||||
const char *uuid,
|
||||
guint priority,
|
||||
NMSettingIP4Config *s_ip4,
|
||||
guint32 timeout,
|
||||
GByteArray *dhcp_anycast_addr);
|
||||
@@ -76,6 +77,7 @@ NMDHCPClient * nm_dhcp_manager_start_ip6 (NMDHCPManager *manager,
|
||||
const char *iface,
|
||||
const GByteArray *hwaddr,
|
||||
const char *uuid,
|
||||
guint priority,
|
||||
NMSettingIP6Config *s_ip6,
|
||||
guint32 timeout,
|
||||
GByteArray *dhcp_anycast_addr,
|
||||
|
@@ -244,7 +244,7 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf)
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_ip4_config_commit (const NMIP4Config *config, int ifindex, int priority)
|
||||
nm_ip4_config_commit (const NMIP4Config *config, int ifindex)
|
||||
{
|
||||
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
|
||||
int mtu = nm_ip4_config_get_mtu (config);
|
||||
@@ -273,17 +273,12 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, int priority)
|
||||
&& nm_ip4_config_destination_is_direct (config, route.network, route.plen))
|
||||
continue;
|
||||
|
||||
/* Don't add the default route when and the connection
|
||||
/* Don't add the default route if the connection
|
||||
* is never supposed to be the default connection.
|
||||
*/
|
||||
if (nm_ip4_config_get_never_default (config) && route.network == 0)
|
||||
continue;
|
||||
|
||||
/* Use the default metric only if the route was created by NM and
|
||||
* didn't already specify a metric.
|
||||
*/
|
||||
if (route.source != NM_PLATFORM_SOURCE_KERNEL && !route.metric)
|
||||
route.metric = priority ? priority : NM_PLATFORM_ROUTE_METRIC_DEFAULT;
|
||||
g_array_append_val (routes, route);
|
||||
}
|
||||
|
||||
|
@@ -60,7 +60,7 @@ const char * nm_ip4_config_get_dbus_path (const NMIP4Config *config);
|
||||
|
||||
/* Integration with nm-platform and nm-setting */
|
||||
NMIP4Config *nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf);
|
||||
gboolean nm_ip4_config_commit (const NMIP4Config *config, int ifindex, int priority);
|
||||
gboolean nm_ip4_config_commit (const NMIP4Config *config, int ifindex);
|
||||
void nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIP4Config *setting);
|
||||
NMSetting *nm_ip4_config_create_setting (const NMIP4Config *config);
|
||||
|
||||
|
@@ -356,7 +356,7 @@ nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6Co
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_ip6_config_commit (const NMIP6Config *config, int ifindex, int priority)
|
||||
nm_ip6_config_commit (const NMIP6Config *config, int ifindex)
|
||||
{
|
||||
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
|
||||
int i;
|
||||
@@ -384,17 +384,12 @@ nm_ip6_config_commit (const NMIP6Config *config, int ifindex, int priority)
|
||||
&& nm_ip6_config_destination_is_direct (config, &route.network, route.plen))
|
||||
continue;
|
||||
|
||||
/* Don't add the default route when and the connection
|
||||
/* Don't add the default route if the connection
|
||||
* is never supposed to be the default connection.
|
||||
*/
|
||||
if (nm_ip6_config_get_never_default (config) && IN6_IS_ADDR_UNSPECIFIED (&route.network))
|
||||
continue;
|
||||
|
||||
/* Use the default metric only if the route was created by NM and
|
||||
* didn't already specify a metric.
|
||||
*/
|
||||
if (route.source != NM_PLATFORM_SOURCE_KERNEL && !route.metric)
|
||||
route.metric = priority ? priority : NM_PLATFORM_ROUTE_METRIC_DEFAULT;
|
||||
g_array_append_val (routes, route);
|
||||
}
|
||||
|
||||
|
@@ -59,7 +59,7 @@ const char * nm_ip6_config_get_dbus_path (const NMIP6Config *config);
|
||||
|
||||
/* Integration with nm-platform and nm-setting */
|
||||
NMIP6Config *nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary);
|
||||
gboolean nm_ip6_config_commit (const NMIP6Config *config, int ifindex, int priority);
|
||||
gboolean nm_ip6_config_commit (const NMIP6Config *config, int ifindex);
|
||||
void nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIP6Config *setting);
|
||||
NMSetting *nm_ip6_config_create_setting (const NMIP6Config *config);
|
||||
|
||||
|
@@ -334,6 +334,7 @@ add_ip4_vpn_gateway_route (NMIP4Config *config, NMDevice *parent_device, guint32
|
||||
route.gateway = 0;
|
||||
|
||||
route.source = NM_PLATFORM_SOURCE_VPN;
|
||||
route.metric = nm_device_get_priority (parent_device);
|
||||
nm_ip4_config_add_route (config, &route);
|
||||
|
||||
/* Ensure there's a route to the parent device's gateway through the
|
||||
@@ -345,6 +346,7 @@ add_ip4_vpn_gateway_route (NMIP4Config *config, NMDevice *parent_device, guint32
|
||||
route.network = parent_gw;
|
||||
route.plen = 32;
|
||||
route.source = NM_PLATFORM_SOURCE_VPN;
|
||||
route.metric = nm_device_get_priority (parent_device);
|
||||
|
||||
nm_ip4_config_add_route (config, &route);
|
||||
}
|
||||
@@ -381,6 +383,7 @@ add_ip6_vpn_gateway_route (NMIP6Config *config,
|
||||
route.gateway = in6addr_any;
|
||||
|
||||
route.source = NM_PLATFORM_SOURCE_VPN;
|
||||
route.metric = nm_device_get_priority (parent_device);
|
||||
nm_ip6_config_add_route (config, &route);
|
||||
|
||||
/* Ensure there's a route to the parent device's gateway through the
|
||||
@@ -392,6 +395,7 @@ add_ip6_vpn_gateway_route (NMIP6Config *config,
|
||||
route.network = *parent_gw;
|
||||
route.plen = 128;
|
||||
route.source = NM_PLATFORM_SOURCE_VPN;
|
||||
route.metric = nm_device_get_priority (parent_device);
|
||||
|
||||
nm_ip6_config_add_route (config, &route);
|
||||
}
|
||||
@@ -694,12 +698,12 @@ nm_vpn_connection_apply_config (NMVPNConnection *connection)
|
||||
nm_platform_link_set_up (priv->ip_ifindex);
|
||||
|
||||
if (priv->ip4_config) {
|
||||
if (!nm_ip4_config_commit (priv->ip4_config, priv->ip_ifindex, 0))
|
||||
if (!nm_ip4_config_commit (priv->ip4_config, priv->ip_ifindex))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (priv->ip6_config) {
|
||||
if (!nm_ip6_config_commit (priv->ip6_config, priv->ip_ifindex, 0))
|
||||
if (!nm_ip6_config_commit (priv->ip6_config, priv->ip_ifindex))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -907,6 +911,20 @@ nm_vpn_connection_config_get (DBusGProxy *proxy,
|
||||
g_clear_object (&priv->ip6_config);
|
||||
}
|
||||
|
||||
static guint
|
||||
vpn_routing_metric (NMVPNConnection *connection)
|
||||
{
|
||||
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
|
||||
|
||||
if (priv->ip_ifindex)
|
||||
return NM_PLATFORM_ROUTE_METRIC_DEFAULT;
|
||||
else {
|
||||
NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (connection));
|
||||
|
||||
return nm_device_get_priority (parent_dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
|
||||
GHashTable *config_hash,
|
||||
@@ -1033,6 +1051,7 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
|
||||
route.plen = nm_ip4_route_get_prefix (item);
|
||||
route.gateway = nm_ip4_route_get_next_hop (item);
|
||||
route.source = NM_PLATFORM_SOURCE_VPN;
|
||||
route.metric = vpn_routing_metric (connection);
|
||||
|
||||
/* Ignore host routes to the VPN gateway since NM adds one itself
|
||||
* below. Since NM knows more about the routing situation than
|
||||
@@ -1179,6 +1198,7 @@ nm_vpn_connection_ip6_config_get (DBusGProxy *proxy,
|
||||
route.plen = nm_ip6_route_get_prefix (item);
|
||||
route.gateway = *nm_ip6_route_get_next_hop (item);
|
||||
route.source = NM_PLATFORM_SOURCE_VPN;
|
||||
route.metric = vpn_routing_metric (connection);
|
||||
|
||||
/* Ignore host routes to the VPN gateway since NM adds one itself
|
||||
* below. Since NM knows more about the routing situation than
|
||||
|
Reference in New Issue
Block a user