platform: add routing-rule add/delete netlink functions

This commit is contained in:
Thomas Haller 2019-03-05 12:13:04 +01:00
parent 9934a6a0e3
commit 9992ac1cf8
4 changed files with 200 additions and 11 deletions

View file

@ -38,7 +38,7 @@ NM-colorize() {
GREP_COLOR='01;31' grep -a --color=always '^\|^\(.* \)\?<\(warn> \|error>\) \[[0-9.]*\]' | \
GREP_COLOR='01;33' grep -a --color=always '^\|^\(.* \)\?<info> \[[0-9.]*\]\( .*\<is starting\>.*$\)\?' | \
GREP_COLOR='01;37' grep -a --color=always '^\|\<platform:\( (.*)\)\? signal: .*$' | \
GREP_COLOR='01;34' grep -a --color=always '^\|\<platform\(-linux\)\?:\( (.*)\)\? link: \(add\|adding\|change\|setting\|deleting\)\>\|\<platform:\( (.*)\)\? address: \(deleting\|adding or updating\) IPv. address:\? \|\<platform:\( (.*)\)\? \(route\|ip4-route\|ip6-route\|qdisc\|tfilter\): \([a-z]\+\|adding or updating\|new\[0x[0-9A-Za-z]*\]\) \|\<platform-linux: sysctl: setting ' | \
GREP_COLOR='01;34' grep -a --color=always '^\|\<platform\(-linux\)\?:\( (.*)\)\? link: \(add\|adding\|change\|setting\|deleting\)\>\|\<platform: routing-rule: \(adding or updating:\|delete \)\|\<platform:\( (.*)\)\? address: \(deleting\|adding or updating\) IPv. address:\? \|\<platform:\( (.*)\)\? \(route\|ip4-route\|ip6-route\|qdisc\|tfilter\): \([a-z]\+\|adding or updating\|new\[0x[0-9A-Za-z]*\]\) \|\<platform-linux: sysctl: setting ' | \
GREP_COLOR='01;35' grep -a --color=always '^\|\<audit: .*$' | \
GREP_COLOR='01;32' grep -a --color=always '^\|\<device (.*): state change: ' |
if [[ "$NM_LOG_GREP" != "" ]]; then

View file

@ -4092,6 +4092,119 @@ nla_put_failure:
g_return_val_if_reached (NULL);
}
static struct nl_msg *
_nl_msg_new_routing_rule (int nlmsg_type,
int nlmsg_flags,
const NMPlatformRoutingRule *routing_rule)
{
nm_auto_nlmsg struct nl_msg *msg = NULL;
const guint8 addr_size = nm_utils_addr_family_to_size (routing_rule->addr_family);
guint32 table;
msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags);
table = routing_rule->table;
if ( NM_IN_SET (routing_rule->addr_family, AF_INET, AF_INET6)
&& routing_rule->action == FR_ACT_TO_TBL
&& routing_rule->l3mdev == 0
&& table == RT_TABLE_UNSPEC) {
/* for IPv6, this setting is invalid and rejected by kernel. That's fine.
*
* for IPv4, kernel will automatically assign an unused table. That's not
* fine, because we don't know what we will get.
*
* The caller must not allow that to happen. */
nm_assert_not_reached ();
}
{
const struct fib_rule_hdr frh = {
.family = routing_rule->addr_family,
.src_len = routing_rule->src_len,
.dst_len = routing_rule->dst_len,
.tos = routing_rule->tos,
.table = table,
.action = routing_rule->action,
/* we only allow setting the "not" flag. */
.flags = routing_rule->flags & ((guint32) FIB_RULE_INVERT),
};
if (nlmsg_append_struct (msg, &frh) < 0)
goto nla_put_failure;
}
if (table > G_MAXINT8)
NLA_PUT_U32 (msg, FRA_TABLE, table);
if (routing_rule->suppress_prefixlen_inverse != 0)
NLA_PUT_U32 (msg, FRA_SUPPRESS_PREFIXLEN, ~routing_rule->suppress_prefixlen_inverse);
if (routing_rule->suppress_ifgroup_inverse != 0)
NLA_PUT_U32 (msg, FRA_SUPPRESS_IFGROUP, ~routing_rule->suppress_ifgroup_inverse);
if (routing_rule->iifname[0] != '\0')
NLA_PUT_STRING (msg, FRA_IIFNAME, routing_rule->iifname);
if (routing_rule->oifname[0] != '\0')
NLA_PUT_STRING (msg, FRA_OIFNAME, routing_rule->oifname);
/* we always set the priority and don't support letting kernel pick one. */
NLA_PUT_U32 (msg, FRA_PRIORITY, routing_rule->priority);
if ( routing_rule->fwmark != 0
|| routing_rule->fwmask != 0) {
NLA_PUT_U32 (msg, FRA_FWMARK, routing_rule->fwmark);
NLA_PUT_U32 (msg, FRA_FWMASK, routing_rule->fwmask);
}
if (routing_rule->src_len > 0)
NLA_PUT (msg, FRA_SRC, addr_size, &routing_rule->src);
if (routing_rule->dst_len > 0)
NLA_PUT (msg, FRA_DST, addr_size, &routing_rule->dst);
if (routing_rule->flow != 0) {
/* only relevant for IPv4. */
NLA_PUT_U32 (msg, FRA_FLOW, routing_rule->flow);
}
if (routing_rule->tun_id != 0)
NLA_PUT_U64 (msg, FRA_TUN_ID, htobe64 (routing_rule->tun_id));
if (routing_rule->l3mdev)
NLA_PUT_U8 (msg, FRA_L3MDEV, routing_rule->l3mdev);
if (routing_rule->protocol != RTPROT_UNSPEC)
NLA_PUT_U8 (msg, FRA_PROTOCOL, routing_rule->protocol);
if (routing_rule->ip_proto != 0)
NLA_PUT_U8 (msg, FRA_IP_PROTO, routing_rule->ip_proto);
if ( routing_rule->sport_range.start
|| routing_rule->sport_range.end)
NLA_PUT (msg, FRA_SPORT_RANGE, sizeof (routing_rule->sport_range), &routing_rule->sport_range);
if ( routing_rule->dport_range.start
|| routing_rule->dport_range.end)
NLA_PUT (msg, FRA_DPORT_RANGE, sizeof (routing_rule->dport_range), &routing_rule->dport_range);
if (routing_rule->uid_range_has)
NLA_PUT (msg, FRA_UID_RANGE, sizeof (routing_rule->uid_range), &routing_rule->uid_range);
switch (routing_rule->action) {
case FR_ACT_GOTO:
NLA_PUT_U32 (msg, FRA_GOTO, routing_rule->goto_target);
break;
}
return g_steal_pointer (&msg);
nla_put_failure:
g_return_val_if_reached (NULL);
}
static struct nl_msg *
_nl_msg_new_qdisc (int nlmsg_type,
int nlmsg_flags,
@ -7916,6 +8029,9 @@ object_delete (NMPlatform *platform,
case NMP_OBJECT_TYPE_IP6_ROUTE:
nlmsg = _nl_msg_new_route (RTM_DELROUTE, 0, obj);
break;
case NMP_OBJECT_TYPE_ROUTING_RULE:
nlmsg = _nl_msg_new_routing_rule (RTM_DELRULE, 0, NMP_OBJECT_CAST_ROUTING_RULE (obj));
break;
case NMP_OBJECT_TYPE_QDISC:
nlmsg = _nl_msg_new_qdisc (RTM_DELQDISC, 0, NMP_OBJECT_CAST_QDISC (obj));
break;
@ -8012,6 +8128,47 @@ ip_route_get (NMPlatform *platform,
/*****************************************************************************/
static int
routing_rule_add (NMPlatform *platform,
NMPNlmFlags flags,
const NMPlatformRoutingRule *routing_rule)
{
WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
nm_auto_nlmsg struct nl_msg *msg = NULL;
gs_free char *errmsg = NULL;
char s_buf[256];
int nle;
msg = _nl_msg_new_routing_rule (RTM_NEWRULE, flags, routing_rule);
event_handler_read_netlink (platform, FALSE);
nle = _nl_send_nlmsg (platform, msg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL);
if (nle < 0) {
_LOGE ("do-add-rule: failed sending netlink request \"%s\" (%d)",
nm_strerror (nle), -nle);
return -NME_PL_NETLINK;
}
delayed_action_handle_all (platform, FALSE);
nm_assert (seq_result);
_NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK
? LOGL_DEBUG
: LOGL_WARN,
"do-add-rule: %s",
wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf)));
if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK)
return 0;
if (seq_result < 0)
return seq_result;
return -NME_UNSPEC;
}
/*****************************************************************************/
static int
qdisc_add (NMPlatform *platform,
NMPNlmFlags flags,
@ -8859,6 +9016,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->ip_route_add = ip_route_add;
platform_class->ip_route_get = ip_route_get;
platform_class->routing_rule_add = routing_rule_add;
platform_class->qdisc_add = qdisc_add;
platform_class->tfilter_add = tfilter_add;

View file

@ -4619,17 +4619,24 @@ nm_platform_object_delete (NMPlatform *self,
_CHECK_SELF (self, klass, FALSE);
if (!NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE,
NMP_OBJECT_TYPE_IP6_ROUTE,
NMP_OBJECT_TYPE_QDISC,
NMP_OBJECT_TYPE_TFILTER))
switch (NMP_OBJECT_GET_TYPE (obj)) {
case NMP_OBJECT_TYPE_ROUTING_RULE:
_LOGD ("%s: delete %s",
NMP_OBJECT_GET_CLASS (obj)->obj_type_name,
nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
break;
case NMP_OBJECT_TYPE_IP4_ROUTE:
case NMP_OBJECT_TYPE_IP6_ROUTE:
case NMP_OBJECT_TYPE_QDISC:
case NMP_OBJECT_TYPE_TFILTER:
ifindex = NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (obj)->ifindex;
_LOG3D ("%s: delete %s",
NMP_OBJECT_GET_CLASS (obj)->obj_type_name,
nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
break;
default:
g_return_val_if_reached (FALSE);
ifindex = NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (obj)->ifindex;
_LOG3D ("%s: delete %s",
NMP_OBJECT_GET_CLASS (obj)->obj_type_name,
nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
}
return klass->object_delete (self, obj);
}
@ -4958,6 +4965,21 @@ nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self,
/*****************************************************************************/
int
nm_platform_routing_rule_add (NMPlatform *self,
NMPNlmFlags flags,
const NMPlatformRoutingRule *routing_rule)
{
_CHECK_SELF (self, klass, -NME_BUG);
g_return_val_if_fail (routing_rule, -NME_BUG);
_LOGD ("routing-rule: adding or updating: %s", nm_platform_routing_rule_to_string (routing_rule, NULL, 0));
return klass->routing_rule_add (self, flags, routing_rule);
}
/*****************************************************************************/
int
nm_platform_qdisc_add (NMPlatform *self,
NMPNlmFlags flags,

View file

@ -1035,6 +1035,10 @@ typedef struct {
int oif_ifindex,
NMPObject **out_route);
int (*routing_rule_add) (NMPlatform *self,
NMPNlmFlags flags,
const NMPlatformRoutingRule *routing_rule);
int (*qdisc_add) (NMPlatform *self,
NMPNlmFlags flags,
const NMPlatformQdisc *qdisc);
@ -1543,6 +1547,10 @@ int nm_platform_ip_route_get (NMPlatform *self,
int oif_ifindex,
NMPObject **out_route);
int nm_platform_routing_rule_add (NMPlatform *self,
NMPNlmFlags flags,
const NMPlatformRoutingRule *routing_rule);
int nm_platform_qdisc_add (NMPlatform *self,
NMPNlmFlags flags,
const NMPlatformQdisc *qdisc);