rtnl_flower_set_vlan_id - not work
I call rtnl_flower_set_vlan_id , but it doesn't have any effect
I should get the following output
filter parent ffff: protocol 802.1Q pref 4 flower chain 0
filter parent ffff: protocol 802.1Q pref 4 flower chain 0 handle 0x1
vlan_id 101
not_in_hw
action order 1: skbedit mark 11 pipe
index 1 ref 1 bind 1
but I get this output
filter parent ffff: protocol 802.1Q pref 1 flower chain 0
filter parent ffff: protocol 802.1Q pref 1 flower chain 0 handle 0x1
not_in_hw
action order 1: skbedit mark 11 pipe
index 1 ref 1 bind 1
void add_flower_filter(struct rtnl_link *link, uint32_t parent_handle, struct nl_sock* sock, int prio, struct rtnl_act* act, uint16_t vlan_id) {
struct rtnl_cls *filter;
int err;
filter = rtnl_cls_alloc();
rtnl_tc_set_link(TC_CAST(filter), link);
rtnl_tc_set_parent(TC_CAST(filter), parent_handle);
err = rtnl_tc_set_kind(TC_CAST(filter), "flower");
throw_err(err);
rtnl_cls_set_prio(filter, prio);
rtnl_cls_set_protocol(filter, ETH_P_8021Q);
err = rtnl_flower_set_vlan_id(filter, vlan_id);
throw_err(err);
err = rtnl_flower_append_action(filter, act);
throw_err(err);
err = rtnl_cls_add(sock, filter, NLM_F_CREATE);
throw_err(err);
rtnl_cls_put(filter);
}
hi. I don't know the answer to this, but since you are able to reproduce, you seem well positioned to find out what's wrong.
Note that kernel sources seem to indicate that this should be a big-endian u16 number. libnl doesn't seem to be aware of that, and just passes on whatever it has. Does it work if you pass 0x6500u instead of 0x65u (101)?
Note that kernel sources seem to indicate that this should be a big-endian u16 number. libnl doesn't seem to be aware of that, and just passes on whatever it has. Does it work if you pass 0x6500u instead of 0x65u (101)?
Hm, no from the kernel sources it seems it's native endianness, although there are comments like TCA_FLOWER_KEY_VLAN_ID, /* be16 */ ... dunno.
it didn't help. didn't help. Do you have any other ideas? full code for testing
#include <iostream>
#include <netlink/netlink.h>
#include <netlink/route/link.h>
#include <netlink/route/tc.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/classifier.h>
#include <linux/if_ether.h>
#include <linux/pkt_cls.h>
#include <linux/netlink.h>
#include <netlink/route/cls/flower.h>
#include <netlink/route/cls/u32.h>
#include <netlink/route/act/skbedit.h>
void throw_err(int err) {
if (err) {
std::string error_str = "!!ERROR " + std::string(nl_geterror(err));
throw std::runtime_error(error_str);
}
}
void add_qdisc_ingress(struct rtnl_link *link, uint32_t parent_handle, uint32_t handle, struct nl_sock* sock) {
int err;
struct rtnl_qdisc *qdisc;
qdisc = rtnl_qdisc_alloc();
rtnl_tc_set_link(TC_CAST(qdisc), link);
rtnl_tc_set_parent(TC_CAST(qdisc), parent_handle);
rtnl_tc_set_handle(TC_CAST(qdisc), handle);
err = rtnl_tc_set_kind(TC_CAST(qdisc), "ingress");
throw_err(err);
err = rtnl_qdisc_add(sock, qdisc, NLM_F_CREATE);
throw_err(err);
rtnl_qdisc_put(qdisc);
}
void add_flower_filter(struct rtnl_link *link, uint32_t parent_handle, struct nl_sock* sock, int prio, struct rtnl_act* act, uint16_t vlan_id) {
struct rtnl_cls *filter;
int err;
filter = rtnl_cls_alloc();
rtnl_tc_set_link(TC_CAST(filter), link);
rtnl_tc_set_parent(TC_CAST(filter), parent_handle);
err = rtnl_tc_set_kind(TC_CAST(filter), "flower");
throw_err(err);
rtnl_cls_set_prio(filter, prio);
rtnl_cls_set_protocol(filter, ETH_P_8021Q);
err = rtnl_flower_set_vlan_id(filter, vlan_id);
throw_err(err);
err = rtnl_flower_append_action(filter, act);
throw_err(err);
err = rtnl_cls_add(sock, filter, NLM_F_CREATE);
throw_err(err);
rtnl_cls_put(filter);
}
int main() {
struct nl_cache *cache;
struct rtnl_link *link;
struct nl_sock *sock;
int if_index;
sock = nl_socket_alloc();
nl_connect(sock, NETLINK_ROUTE);
rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache);
link = rtnl_link_get_by_name(cache, "lo");
struct rtnl_qdisc *qdisc;
if (!(qdisc = rtnl_qdisc_alloc())) {
std::runtime_error("Can not allocate Qdisc");
}
rtnl_tc_set_link(TC_CAST(qdisc), link);
rtnl_tc_set_parent(TC_CAST(qdisc), TC_HANDLE(0xffff, 0));
//tc qdisc del dev lo ingress
rtnl_qdisc_delete(sock, qdisc);
free(qdisc);
//tc qdisc add dev lo ingress
add_qdisc_ingress(link, TC_H_INGRESS, TC_HANDLE(0xffff, 0), sock);
struct rtnl_act *act = rtnl_act_alloc();
if (!act) {
printf("rtnl_act_alloc() returns %p\n", act);
return -1;
}
rtnl_tc_set_kind(TC_CAST(act), "skbedit");
rtnl_skbedit_set_action(act, TC_ACT_PIPE);
rtnl_skbedit_set_mark(act, 11);
add_flower_filter(link, TC_HANDLE(0xffff, 0), sock, 1, act, 0x6500u);
return 0;
}
-
check with a non-libnl3 tool whether the vlan-id is set. I am not familiar with this, but some
tccommand line should show it, when it's set. If you can see it there, then libnl fails to parse the data from kernel. If it's not there, libnl fails to configure it in kernel. -
run with
strace -v -s 1000 ./my-command(or something like that), and try to see what netlink messages are exchanged. -
from looking at the libnl code, it would seem that libnl should try to set the value in the netlink message. If not, investigate why not. If yes, investigate why kernel ignores it (maybe the value makes no sense for the object you are configuring).
-
can you create the desired configuration with other tools, e.g. some
tccommand line? If yes, check which netlink messages are exchanged, and how they differ from what libnl does.