Merge branch 'mptcp-userspace-pm'

Matthieu Baerts says:

====================
mptcp: userspace pm: 'dump addrs' and 'get addr'

This series from Geliang adds two new Netlink commands to the userspace
PM:

- one to dump all addresses of a specific MPTCP connection:
  - feature added in patches 3 to 5
  - test added in patches 7, 8 and 10

- and one to get a specific address for an MPTCP connection:
  - feature added in patches 11 to 13
  - test added in patches 14 and 15

These new Netlink commands can be useful if an MPTCP daemon lost track
of the different connections, e.g. after having been restarted.

The other patches are some clean-ups and small improvements added
while working on the new features.

====================

Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
This commit is contained in:
David S. Miller 2024-03-04 13:07:46 +00:00
commit 09fcde5477
11 changed files with 374 additions and 50 deletions

View File

@ -292,13 +292,14 @@ operations:
-
name: get-addr
doc: Get endpoint information
attribute-set: endpoint
attribute-set: attr
dont-validate: [ strict ]
flags: [ uns-admin-perm ]
do: &get-addr-attrs
request:
attributes:
- addr
- token
reply:
attributes:
- addr

View File

@ -32,8 +32,9 @@ const struct nla_policy mptcp_pm_del_addr_nl_policy[MPTCP_PM_ENDPOINT_ADDR + 1]
};
/* MPTCP_PM_CMD_GET_ADDR - do */
const struct nla_policy mptcp_pm_get_addr_nl_policy[MPTCP_PM_ENDPOINT_ADDR + 1] = {
[MPTCP_PM_ENDPOINT_ADDR] = NLA_POLICY_NESTED(mptcp_pm_address_nl_policy),
const struct nla_policy mptcp_pm_get_addr_nl_policy[MPTCP_PM_ATTR_TOKEN + 1] = {
[MPTCP_PM_ATTR_ADDR] = NLA_POLICY_NESTED(mptcp_pm_address_nl_policy),
[MPTCP_PM_ATTR_TOKEN] = { .type = NLA_U32, },
};
/* MPTCP_PM_CMD_FLUSH_ADDRS - do */
@ -110,7 +111,7 @@ const struct genl_ops mptcp_pm_nl_ops[11] = {
.doit = mptcp_pm_nl_get_addr_doit,
.dumpit = mptcp_pm_nl_get_addr_dumpit,
.policy = mptcp_pm_get_addr_nl_policy,
.maxattr = MPTCP_PM_ENDPOINT_ADDR,
.maxattr = MPTCP_PM_ATTR_TOKEN,
.flags = GENL_UNS_ADMIN_PERM,
},
{

View File

@ -18,7 +18,7 @@ extern const struct nla_policy mptcp_pm_add_addr_nl_policy[MPTCP_PM_ENDPOINT_ADD
extern const struct nla_policy mptcp_pm_del_addr_nl_policy[MPTCP_PM_ENDPOINT_ADDR + 1];
extern const struct nla_policy mptcp_pm_get_addr_nl_policy[MPTCP_PM_ENDPOINT_ADDR + 1];
extern const struct nla_policy mptcp_pm_get_addr_nl_policy[MPTCP_PM_ATTR_TOKEN + 1];
extern const struct nla_policy mptcp_pm_flush_addrs_nl_policy[MPTCP_PM_ENDPOINT_ADDR + 1];

View File

@ -441,6 +441,22 @@ int mptcp_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, unsigned int id
return mptcp_pm_nl_get_flags_and_ifindex_by_id(msk, id, flags, ifindex);
}
int mptcp_pm_get_addr(struct sk_buff *skb, struct genl_info *info)
{
if (info->attrs[MPTCP_PM_ATTR_TOKEN])
return mptcp_userspace_pm_get_addr(skb, info);
return mptcp_pm_nl_get_addr(skb, info);
}
int mptcp_pm_dump_addr(struct sk_buff *msg, struct netlink_callback *cb)
{
const struct genl_info *info = genl_info_dump(cb);
if (info->attrs[MPTCP_PM_ATTR_TOKEN])
return mptcp_userspace_pm_dump_addr(msg, cb);
return mptcp_pm_nl_dump_addr(msg, cb);
}
int mptcp_pm_set_flags(struct net *net, struct nlattr *token,
struct mptcp_pm_addr_entry *loc,
struct mptcp_pm_addr_entry *rem, u8 bkup)

View File

@ -18,9 +18,6 @@
#include "protocol.h"
#include "mib.h"
/* forward declaration */
static struct genl_family mptcp_genl_family;
static int pm_nl_pernet_id;
struct mptcp_pm_add_entry {
@ -1550,8 +1547,8 @@ void mptcp_pm_remove_addrs(struct mptcp_sock *msk, struct list_head *rm_list)
}
}
void mptcp_pm_remove_addrs_and_subflows(struct mptcp_sock *msk,
struct list_head *rm_list)
static void mptcp_pm_remove_addrs_and_subflows(struct mptcp_sock *msk,
struct list_head *rm_list)
{
struct mptcp_rm_list alist = { .nr = 0 }, slist = { .nr = 0 };
struct mptcp_pm_addr_entry *entry;
@ -1636,8 +1633,8 @@ int mptcp_pm_nl_flush_addrs_doit(struct sk_buff *skb, struct genl_info *info)
return 0;
}
static int mptcp_nl_fill_addr(struct sk_buff *skb,
struct mptcp_pm_addr_entry *entry)
int mptcp_nl_fill_addr(struct sk_buff *skb,
struct mptcp_pm_addr_entry *entry)
{
struct mptcp_addr_info *addr = &entry->addr;
struct nlattr *attr;
@ -1675,7 +1672,7 @@ nla_put_failure:
return -EMSGSIZE;
}
int mptcp_pm_nl_get_addr_doit(struct sk_buff *skb, struct genl_info *info)
int mptcp_pm_nl_get_addr(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *attr = info->attrs[MPTCP_PM_ENDPOINT_ADDR];
struct pm_nl_pernet *pernet = genl_info_pm_nl(info);
@ -1725,8 +1722,13 @@ fail:
return ret;
}
int mptcp_pm_nl_get_addr_dumpit(struct sk_buff *msg,
struct netlink_callback *cb)
int mptcp_pm_nl_get_addr_doit(struct sk_buff *skb, struct genl_info *info)
{
return mptcp_pm_get_addr(skb, info);
}
int mptcp_pm_nl_dump_addr(struct sk_buff *msg,
struct netlink_callback *cb)
{
struct net *net = sock_net(msg->sk);
struct mptcp_pm_addr_entry *entry;
@ -1768,6 +1770,12 @@ int mptcp_pm_nl_get_addr_dumpit(struct sk_buff *msg,
return msg->len;
}
int mptcp_pm_nl_get_addr_dumpit(struct sk_buff *msg,
struct netlink_callback *cb)
{
return mptcp_pm_dump_addr(msg, cb);
}
static int parse_limit(struct genl_info *info, int id, unsigned int *limit)
{
struct nlattr *attr = info->attrs[id];
@ -2281,7 +2289,7 @@ nla_put_failure:
nlmsg_free(skb);
}
static struct genl_family mptcp_genl_family __ro_after_init = {
struct genl_family mptcp_genl_family __ro_after_init = {
.name = MPTCP_PM_NAME,
.version = MPTCP_PM_VER,
.netnsok = true,

View File

@ -106,19 +106,26 @@ static int mptcp_userspace_pm_delete_local_addr(struct mptcp_sock *msk,
return -EINVAL;
}
static struct mptcp_pm_addr_entry *
mptcp_userspace_pm_lookup_addr_by_id(struct mptcp_sock *msk, unsigned int id)
{
struct mptcp_pm_addr_entry *entry;
list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) {
if (entry->addr.id == id)
return entry;
}
return NULL;
}
int mptcp_userspace_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk,
unsigned int id,
u8 *flags, int *ifindex)
{
struct mptcp_pm_addr_entry *entry, *match = NULL;
struct mptcp_pm_addr_entry *match;
spin_lock_bh(&msk->pm.lock);
list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) {
if (id == entry->addr.id) {
match = entry;
break;
}
}
match = mptcp_userspace_pm_lookup_addr_by_id(msk, id);
spin_unlock_bh(&msk->pm.lock);
if (match) {
*flags = match->flags;
@ -261,7 +268,7 @@ int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN];
struct nlattr *id = info->attrs[MPTCP_PM_ATTR_LOC_ID];
struct mptcp_pm_addr_entry *match = NULL;
struct mptcp_pm_addr_entry *match;
struct mptcp_pm_addr_entry *entry;
struct mptcp_sock *msk;
LIST_HEAD(free_list);
@ -298,13 +305,7 @@ int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info)
lock_sock(sk);
list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) {
if (entry->addr.id == id_val) {
match = entry;
break;
}
}
match = mptcp_userspace_pm_lookup_addr_by_id(msk, id_val);
if (!match) {
GENL_SET_ERR_MSG(info, "address with specified id not found");
release_sock(sk);
@ -334,7 +335,6 @@ int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info)
struct nlattr *laddr = info->attrs[MPTCP_PM_ATTR_ADDR];
struct mptcp_pm_addr_entry local = { 0 };
struct mptcp_addr_info addr_r;
struct mptcp_addr_info addr_l;
struct mptcp_sock *msk;
int err = -EINVAL;
struct sock *sk;
@ -360,25 +360,31 @@ int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info)
goto create_err;
}
err = mptcp_pm_parse_addr(laddr, info, &addr_l);
err = mptcp_pm_parse_entry(laddr, info, true, &local);
if (err < 0) {
NL_SET_ERR_MSG_ATTR(info->extack, laddr, "error parsing local addr");
goto create_err;
}
if (local.flags & MPTCP_PM_ADDR_FLAG_SIGNAL) {
GENL_SET_ERR_MSG(info, "invalid addr flags");
err = -EINVAL;
goto create_err;
}
local.flags |= MPTCP_PM_ADDR_FLAG_SUBFLOW;
err = mptcp_pm_parse_addr(raddr, info, &addr_r);
if (err < 0) {
NL_SET_ERR_MSG_ATTR(info->extack, raddr, "error parsing remote addr");
goto create_err;
}
if (!mptcp_pm_addr_families_match(sk, &addr_l, &addr_r)) {
if (!mptcp_pm_addr_families_match(sk, &local.addr, &addr_r)) {
GENL_SET_ERR_MSG(info, "families mismatch");
err = -EINVAL;
goto create_err;
}
local.addr = addr_l;
err = mptcp_userspace_pm_append_new_local_addr(msk, &local, false);
if (err < 0) {
GENL_SET_ERR_MSG(info, "did not match address and id");
@ -387,7 +393,7 @@ int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info)
lock_sock(sk);
err = __mptcp_subflow_connect(sk, &addr_l, &addr_r);
err = __mptcp_subflow_connect(sk, &local.addr, &addr_r);
release_sock(sk);
@ -572,3 +578,137 @@ set_flags_err:
sock_put(sk);
return ret;
}
int mptcp_userspace_pm_dump_addr(struct sk_buff *msg,
struct netlink_callback *cb)
{
struct id_bitmap {
DECLARE_BITMAP(map, MPTCP_PM_MAX_ADDR_ID + 1);
} *bitmap;
const struct genl_info *info = genl_info_dump(cb);
struct net *net = sock_net(msg->sk);
struct mptcp_pm_addr_entry *entry;
struct mptcp_sock *msk;
struct nlattr *token;
int ret = -EINVAL;
struct sock *sk;
void *hdr;
bitmap = (struct id_bitmap *)cb->ctx;
token = info->attrs[MPTCP_PM_ATTR_TOKEN];
msk = mptcp_token_get_sock(net, nla_get_u32(token));
if (!msk) {
NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token");
return ret;
}
sk = (struct sock *)msk;
if (!mptcp_pm_is_userspace(msk)) {
GENL_SET_ERR_MSG(info, "invalid request; userspace PM not selected");
goto out;
}
lock_sock(sk);
spin_lock_bh(&msk->pm.lock);
list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) {
if (test_bit(entry->addr.id, bitmap->map))
continue;
hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, &mptcp_genl_family,
NLM_F_MULTI, MPTCP_PM_CMD_GET_ADDR);
if (!hdr)
break;
if (mptcp_nl_fill_addr(msg, entry) < 0) {
genlmsg_cancel(msg, hdr);
break;
}
__set_bit(entry->addr.id, bitmap->map);
genlmsg_end(msg, hdr);
}
spin_unlock_bh(&msk->pm.lock);
release_sock(sk);
ret = msg->len;
out:
sock_put(sk);
return ret;
}
int mptcp_userspace_pm_get_addr(struct sk_buff *skb,
struct genl_info *info)
{
struct nlattr *attr = info->attrs[MPTCP_PM_ENDPOINT_ADDR];
struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN];
struct mptcp_pm_addr_entry addr, *entry;
struct net *net = sock_net(skb->sk);
struct mptcp_sock *msk;
struct sk_buff *msg;
int ret = -EINVAL;
struct sock *sk;
void *reply;
msk = mptcp_token_get_sock(net, nla_get_u32(token));
if (!msk) {
NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token");
return ret;
}
sk = (struct sock *)msk;
if (!mptcp_pm_is_userspace(msk)) {
GENL_SET_ERR_MSG(info, "invalid request; userspace PM not selected");
goto out;
}
ret = mptcp_pm_parse_entry(attr, info, false, &addr);
if (ret < 0)
goto out;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) {
ret = -ENOMEM;
goto out;
}
reply = genlmsg_put_reply(msg, info, &mptcp_genl_family, 0,
info->genlhdr->cmd);
if (!reply) {
GENL_SET_ERR_MSG(info, "not enough space in Netlink message");
ret = -EMSGSIZE;
goto fail;
}
lock_sock(sk);
spin_lock_bh(&msk->pm.lock);
entry = mptcp_userspace_pm_lookup_addr_by_id(msk, addr.addr.id);
if (!entry) {
GENL_SET_ERR_MSG(info, "address not found");
ret = -EINVAL;
goto unlock_fail;
}
ret = mptcp_nl_fill_addr(msg, entry);
if (ret)
goto unlock_fail;
genlmsg_end(msg, reply);
ret = genlmsg_reply(msg, info);
spin_unlock_bh(&msk->pm.lock);
release_sock(sk);
sock_put(sk);
return ret;
unlock_fail:
spin_unlock_bh(&msk->pm.lock);
release_sock(sk);
fail:
nlmsg_free(msg);
out:
sock_put(sk);
return ret;
}

View File

@ -343,6 +343,8 @@ struct mptcp_sock {
#define mptcp_for_each_subflow_safe(__msk, __subflow, __tmp) \
list_for_each_entry_safe(__subflow, __tmp, &((__msk)->conn_list), node)
extern struct genl_family mptcp_genl_family;
static inline void msk_owned_by_me(const struct mptcp_sock *msk)
{
sock_owned_by_me((const struct sock *)msk);
@ -981,8 +983,6 @@ int mptcp_pm_announce_addr(struct mptcp_sock *msk,
int mptcp_pm_remove_addr(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_list);
int mptcp_pm_remove_subflow(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_list);
void mptcp_pm_remove_addrs(struct mptcp_sock *msk, struct list_head *rm_list);
void mptcp_pm_remove_addrs_and_subflows(struct mptcp_sock *msk,
struct list_head *rm_list);
void mptcp_free_local_addr_list(struct mptcp_sock *msk);
@ -998,6 +998,8 @@ void __mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflo
const struct mptcp_options_received *mp_opt);
void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subflow,
struct request_sock *req);
int mptcp_nl_fill_addr(struct sk_buff *skb,
struct mptcp_pm_addr_entry *entry);
static inline bool mptcp_pm_should_add_signal(struct mptcp_sock *msk)
{
@ -1062,6 +1064,15 @@ bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc);
int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc);
int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc);
int mptcp_pm_dump_addr(struct sk_buff *msg, struct netlink_callback *cb);
int mptcp_pm_nl_dump_addr(struct sk_buff *msg,
struct netlink_callback *cb);
int mptcp_userspace_pm_dump_addr(struct sk_buff *msg,
struct netlink_callback *cb);
int mptcp_pm_get_addr(struct sk_buff *skb, struct genl_info *info);
int mptcp_pm_nl_get_addr(struct sk_buff *skb, struct genl_info *info);
int mptcp_userspace_pm_get_addr(struct sk_buff *skb,
struct genl_info *info);
static inline u8 subflow_get_local_id(const struct mptcp_subflow_context *subflow)
{

View File

@ -21,6 +21,7 @@ cinfail=""
cinsent=""
tmpfile=""
cout=""
err=""
capout=""
ns1=""
ns2=""
@ -189,6 +190,7 @@ init() {
cin=$(mktemp)
cinsent=$(mktemp)
cout=$(mktemp)
err=$(mktemp)
evts_ns1=$(mktemp)
evts_ns2=$(mktemp)
@ -204,6 +206,7 @@ cleanup()
rm -f "$sin" "$sout" "$cinsent" "$cinfail"
rm -f "$tmpfile"
rm -rf $evts_ns1 $evts_ns2
rm -f "$err"
cleanup_partial
}
@ -3356,6 +3359,77 @@ userspace_pm_rm_sf()
wait_rm_sf $1 "${cnt}"
}
check_output()
{
local cmd="$1"
local expected="$2"
local msg="$3"
local rc=0
mptcp_lib_check_output "${err}" "${cmd}" "${expected}" || rc=${?}
if [ ${rc} -eq 2 ]; then
fail_test "fail to check output # error ${rc}"
elif [ ${rc} -eq 0 ]; then
print_ok
elif [ ${rc} -eq 1 ]; then
fail_test "fail to check output # different output"
fi
}
# $1: ns
userspace_pm_dump()
{
local evts=$evts_ns1
local tk
[ "$1" == "$ns2" ] && evts=$evts_ns2
tk=$(mptcp_lib_evts_get_info token "$evts")
ip netns exec $1 ./pm_nl_ctl dump token $tk
}
# $1: ns ; $2: id
userspace_pm_get_addr()
{
local evts=$evts_ns1
local tk
[ "$1" == "$ns2" ] && evts=$evts_ns2
tk=$(mptcp_lib_evts_get_info token "$evts")
ip netns exec $1 ./pm_nl_ctl get $2 token $tk
}
userspace_pm_chk_dump_addr()
{
local ns="${1}"
local exp="${2}"
local check="${3}"
print_check "dump addrs ${check}"
if mptcp_lib_kallsyms_has "mptcp_userspace_pm_dump_addr$"; then
check_output "userspace_pm_dump ${ns}" "${exp}"
else
print_skip
fi
}
userspace_pm_chk_get_addr()
{
local ns="${1}"
local id="${2}"
local exp="${3}"
print_check "get id ${id} addr"
if mptcp_lib_kallsyms_has "mptcp_userspace_pm_get_addr$"; then
check_output "userspace_pm_get_addr ${ns} ${id}" "${exp}"
else
print_skip
fi
}
userspace_tests()
{
# userspace pm type prevents add_addr
@ -3447,10 +3521,18 @@ userspace_tests()
chk_mptcp_info subflows 2 subflows 2
chk_subflows_total 3 3
chk_mptcp_info add_addr_signal 2 add_addr_accepted 2
userspace_pm_chk_dump_addr "${ns1}" \
$'id 10 flags signal 10.0.2.1\nid 20 flags signal 10.0.3.1' \
"signal"
userspace_pm_chk_get_addr "${ns1}" "10" "id 10 flags signal 10.0.2.1"
userspace_pm_chk_get_addr "${ns1}" "20" "id 20 flags signal 10.0.3.1"
userspace_pm_rm_addr $ns1 10
userspace_pm_rm_sf $ns1 "::ffff:10.0.2.1" $SUB_ESTABLISHED
userspace_pm_chk_dump_addr "${ns1}" \
"id 20 flags signal 10.0.3.1" "after rm_addr 10"
userspace_pm_rm_addr $ns1 20
userspace_pm_rm_sf $ns1 10.0.3.1 $SUB_ESTABLISHED
userspace_pm_chk_dump_addr "${ns1}" "" "after rm_addr 20"
chk_rm_nr 2 2 invert
chk_mptcp_info subflows 0 subflows 0
chk_subflows_total 1 1
@ -3471,8 +3553,15 @@ userspace_tests()
chk_join_nr 1 1 1
chk_mptcp_info subflows 1 subflows 1
chk_subflows_total 2 2
userspace_pm_chk_dump_addr "${ns2}" \
"id 20 flags subflow 10.0.3.2" \
"subflow"
userspace_pm_chk_get_addr "${ns2}" "20" "id 20 flags subflow 10.0.3.2"
userspace_pm_rm_addr $ns2 20
userspace_pm_rm_sf $ns2 10.0.3.2 $SUB_ESTABLISHED
userspace_pm_chk_dump_addr "${ns2}" \
"" \
"after rm_addr 20"
chk_rm_nr 1 1
chk_mptcp_info subflows 0 subflows 0
chk_subflows_total 1 1
@ -3492,6 +3581,8 @@ userspace_tests()
chk_mptcp_info subflows 0 subflows 0
chk_subflows_total 1 1
userspace_pm_add_sf $ns2 10.0.3.2 0
userspace_pm_chk_dump_addr "${ns2}" \
"id 0 flags subflow 10.0.3.2" "id 0 subflow"
chk_join_nr 1 1 1
chk_mptcp_info subflows 1 subflows 1
chk_subflows_total 2 2

View File

@ -319,3 +319,26 @@ mptcp_lib_wait_local_port_listen() {
sleep 0.1
done
}
mptcp_lib_check_output() {
local err="${1}"
local cmd="${2}"
local expected="${3}"
local cmd_ret=0
local out
if ! out=$(${cmd} 2>"${err}"); then
cmd_ret=${?}
fi
if [ ${cmd_ret} -ne 0 ]; then
mptcp_lib_print_err "[FAIL] command execution '${cmd}' stderr"
cat "${err}"
return 2
elif [ "${out}" = "${expected}" ]; then
return 0
else
mptcp_lib_print_err "[FAIL] expected '${expected}' got '${out}'"
return 1
fi
}

View File

@ -54,21 +54,17 @@ check()
local cmd="$1"
local expected="$2"
local msg="$3"
local out=`$cmd 2>$err`
local cmd_ret=$?
local rc=0
printf "%-50s" "$msg"
if [ $cmd_ret -ne 0 ]; then
echo "[FAIL] command execution '$cmd' stderr "
cat $err
mptcp_lib_result_fail "${msg} # error ${cmd_ret}"
mptcp_lib_check_output "${err}" "${cmd}" "${expected}" || rc=${?}
if [ ${rc} -eq 2 ]; then
mptcp_lib_result_fail "${msg} # error ${rc}"
ret=1
elif [ "$out" = "$expected" ]; then
echo "[ OK ]"
elif [ ${rc} -eq 0 ]; then
mptcp_lib_print_ok "[ OK ]"
mptcp_lib_result_pass "${msg}"
else
echo -n "[FAIL] "
echo "expected '$expected' got '$out'"
elif [ ${rc} -eq 1 ]; then
mptcp_lib_result_fail "${msg} # different output"
ret=1
fi

View File

@ -453,6 +453,7 @@ int csf(int fd, int pm_family, int argc, char *argv[])
char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1024];
u_int32_t flags = MPTCP_PM_ADDR_FLAG_SUBFLOW;
const char *params[5];
struct nlmsghdr *nh;
struct rtattr *addr;
@ -558,6 +559,13 @@ int csf(int fd, int pm_family, int argc, char *argv[])
off += NLMSG_ALIGN(rta->rta_len);
}
/* addr flags */
rta = (void *)(data + off);
rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS;
rta->rta_len = RTA_LENGTH(4);
memcpy(RTA_DATA(rta), &flags, 4);
off += NLMSG_ALIGN(rta->rta_len);
addr->rta_len = off - addr_start;
}
@ -1079,6 +1087,7 @@ int get_addr(int fd, int pm_family, int argc, char *argv[])
1024];
struct rtattr *rta, *nest;
struct nlmsghdr *nh;
u_int32_t token = 0;
int nest_start;
u_int8_t id;
int off = 0;
@ -1089,10 +1098,12 @@ int get_addr(int fd, int pm_family, int argc, char *argv[])
MPTCP_PM_VER);
/* the only argument is the address id */
if (argc != 3)
if (argc != 3 && argc != 5)
syntax(argv);
id = atoi(argv[2]);
if (argc == 5 && !strcmp(argv[3], "token"))
token = strtoul(argv[4], NULL, 10);
nest_start = off;
nest = (void *)(data + off);
@ -1108,6 +1119,15 @@ int get_addr(int fd, int pm_family, int argc, char *argv[])
off += NLMSG_ALIGN(rta->rta_len);
nest->rta_len = off - nest_start;
/* token */
if (token) {
rta = (void *)(data + off);
rta->rta_type = MPTCP_PM_ATTR_TOKEN;
rta->rta_len = RTA_LENGTH(4);
memcpy(RTA_DATA(rta), &token, 4);
off += NLMSG_ALIGN(rta->rta_len);
}
print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data)));
return 0;
}
@ -1119,8 +1139,16 @@ int dump_addrs(int fd, int pm_family, int argc, char *argv[])
1024];
pid_t pid = getpid();
struct nlmsghdr *nh;
u_int32_t token = 0;
struct rtattr *rta;
int off = 0;
if (argc != 2 && argc != 4)
syntax(argv);
if (argc == 4 && !strcmp(argv[2], "token"))
token = strtoul(argv[3], NULL, 10);
memset(data, 0, sizeof(data));
nh = (void *)data;
off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR,
@ -1130,6 +1158,15 @@ int dump_addrs(int fd, int pm_family, int argc, char *argv[])
nh->nlmsg_pid = pid;
nh->nlmsg_len = off;
/* token */
if (token) {
rta = (void *)(data + off);
rta->rta_type = MPTCP_PM_ATTR_TOKEN;
rta->rta_len = RTA_LENGTH(4);
memcpy(RTA_DATA(rta), &token, 4);
off += NLMSG_ALIGN(rta->rta_len);
}
print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data)));
return 0;
}