/* Specify numa node during map creation */
#define BPF_F_NUMA_NODE (1U << 2)
+#define BPF_OBJ_NAME_LEN 16U
+
union bpf_attr {
struct { /* anonymous struct used by BPF_MAP_CREATE command */
__u32 map_type; /* one of enum bpf_map_type */
__u32 numa_node; /* numa node (effective only if
* BPF_F_NUMA_NODE is set).
*/
+ __u8 map_name[BPF_OBJ_NAME_LEN];
};
struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
__aligned_u64 log_buf; /* user supplied buffer */
__u32 kern_version; /* checked when prog_type=kprobe */
__u32 prog_flags;
+ __u8 prog_name[BPF_OBJ_NAME_LEN];
};
struct { /* anonymous struct used by BPF_OBJ_* commands */
* @map: pointer to sockmap to update
* @key: key to insert/update sock in map
* @flags: same flags as map update elem
+ *
+ * int bpf_xdp_adjust_meta(xdp_md, delta)
+ * Adjust the xdp_md.data_meta by delta
+ * @xdp_md: pointer to xdp_md
+ * @delta: An positive/negative integer to be added to xdp_md.data_meta
+ * Return: 0 on success or negative on error
*/
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
FN(redirect_map), \
FN(sk_redirect_map), \
FN(sock_map_update), \
+ FN(xdp_adjust_meta),
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call
__u32 data_end;
__u32 napi_id;
- /* accessed by BPF_PROG_TYPE_sk_skb types */
+ /* Accessed by BPF_PROG_TYPE_sk_skb types from here to ... */
__u32 family;
__u32 remote_ip4; /* Stored in network byte order */
__u32 local_ip4; /* Stored in network byte order */
__u32 local_ip6[4]; /* Stored in network byte order */
__u32 remote_port; /* Stored in network byte order */
__u32 local_port; /* stored in host byte order */
+ /* ... here. */
+
+ __u32 data_meta;
};
struct bpf_tunnel_key {
struct xdp_md {
__u32 data;
__u32 data_end;
+ __u32 data_meta;
};
enum sk_action {
__u32 xlated_prog_len;
__aligned_u64 jited_prog_insns;
__aligned_u64 xlated_prog_insns;
+ __u64 load_time; /* ns since boottime */
+ __u32 created_by_uid;
+ __u32 nr_map_ids;
+ __aligned_u64 map_ids;
+ __u8 name[BPF_OBJ_NAME_LEN];
} __attribute__((aligned(8)));
struct bpf_map_info {
__u32 value_size;
__u32 max_entries;
__u32 map_flags;
+ __u8 name[BPF_OBJ_NAME_LEN];
} __attribute__((aligned(8)));
/* User bpf_sock_ops struct to access socket values and specify request ops
.IR PRIORITY " | "
.BR vlan_ethtype " { " ipv4 " | " ipv6 " | "
.IR ETH_TYPE " } | "
+.B mpls_label
+.IR LABEL " | "
+.B mpls_tc
+.IR TC " | "
+.B mpls_bos
+.IR BOS " | "
+.B mpls_ttl
+.IR TTL " | "
.BR ip_proto " { " tcp " | " udp " | " sctp " | " icmp " | " icmpv6 " | "
.IR IP_PROTO " } | "
.B ip_tos
.BR ipv4 ", " ipv6
or an unsigned 16bit value in hexadecimal format.
.TP
+.BI mpls_label " LABEL"
+Match the label id in the outermost MPLS label stack entry.
+.I LABEL
+is an unsigned 20 bit value in decimal format.
+.TP
+.BI mpls_tc " TC"
+Match on the MPLS TC field, which is typically used for packet priority,
+in the outermost MPLS label stack entry.
+.I TC
+is an unsigned 3 bit value in decimal format.
+.TP
+.BI mpls_bos " BOS"
+Match on the MPLS Bottom Of Stack field in the outermost MPLS label stack
+entry.
+.I BOS
+is a 1 bit value in decimal format.
+.TP
+.BI mpls_ttl " TTL"
+Match on the MPLS Time To Live field in the outermost MPLS label stack
+entry.
+.I TTL
+is an unsigned 8 bit value in decimal format.
+.TP
.BI ip_proto " IP_PROTO"
Match on layer four protocol.
.I IP_PROTO
As stated above where applicable, matches of a certain layer implicitly depend
on the matches of the next lower layer. Precisely, layer one and two matches
(\fBindev\fR, \fBdst_mac\fR and \fBsrc_mac\fR)
-have no dependency, layer three matches
-(\fBip_proto\fR, \fBdst_ip\fR, \fBsrc_ip\fR, \fBarp_tip\fR, \fBarp_sip\fR,
+have no dependency,
+MPLS and layer three matches
+(\fBmpls_label\fR, \fBmpls_tc\fR, \fBmpls_bos\fR, \fBmpls_ttl\fR,
+\fBip_proto\fR, \fBdst_ip\fR, \fBsrc_ip\fR, \fBarp_tip\fR, \fBarp_sip\fR,
\fBarp_op\fR, \fBarp_tha\fR, \fBarp_sha\fR and \fBip_flags\fR)
depend on the
.B protocol
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tc_act/tc_vlan.h>
+#include <linux/mpls.h>
#include "utils.h"
#include "tc_util.h"
" ip_proto [tcp | udp | sctp | icmp | icmpv6 | IP-PROTO ] |\n"
" ip_tos MASKED-IP_TOS |\n"
" ip_ttl MASKED-IP_TTL |\n"
+ " mpls_label LABEL |\n"
+ " mpls_tc TC |\n"
+ " mpls_bos BOS |\n"
+ " mpls_ttl TTL |\n"
" dst_ip PREFIX |\n"
" src_ip PREFIX |\n"
" dst_port PORT-NUMBER |\n"
&vlan_ethtype, n);
if (ret < 0)
return -1;
+ } else if (matches(*argv, "mpls_label") == 0) {
+ __u32 label;
+
+ NEXT_ARG();
+ if (eth_type != htons(ETH_P_MPLS_UC) &&
+ eth_type != htons(ETH_P_MPLS_MC)) {
+ fprintf(stderr,
+ "Can't set \"mpls_label\" if ethertype isn't MPLS\n");
+ return -1;
+ }
+ ret = get_u32(&label, *argv, 10);
+ if (ret < 0 || label & ~(MPLS_LS_LABEL_MASK >> MPLS_LS_LABEL_SHIFT)) {
+ fprintf(stderr, "Illegal \"mpls_label\"\n");
+ return -1;
+ }
+ addattr32(n, MAX_MSG, TCA_FLOWER_KEY_MPLS_LABEL, label);
+ } else if (matches(*argv, "mpls_tc") == 0) {
+ __u8 tc;
+
+ NEXT_ARG();
+ if (eth_type != htons(ETH_P_MPLS_UC) &&
+ eth_type != htons(ETH_P_MPLS_MC)) {
+ fprintf(stderr,
+ "Can't set \"mpls_tc\" if ethertype isn't MPLS\n");
+ return -1;
+ }
+ ret = get_u8(&tc, *argv, 10);
+ if (ret < 0 || tc & ~(MPLS_LS_TC_MASK >> MPLS_LS_TC_SHIFT)) {
+ fprintf(stderr, "Illegal \"mpls_tc\"\n");
+ return -1;
+ }
+ addattr8(n, MAX_MSG, TCA_FLOWER_KEY_MPLS_TC, tc);
+ } else if (matches(*argv, "mpls_bos") == 0) {
+ __u8 bos;
+
+ NEXT_ARG();
+ if (eth_type != htons(ETH_P_MPLS_UC) &&
+ eth_type != htons(ETH_P_MPLS_MC)) {
+ fprintf(stderr,
+ "Can't set \"mpls_bos\" if ethertype isn't MPLS\n");
+ return -1;
+ }
+ ret = get_u8(&bos, *argv, 10);
+ if (ret < 0 || bos & ~(MPLS_LS_S_MASK >> MPLS_LS_S_SHIFT)) {
+ fprintf(stderr, "Illegal \"mpls_bos\"\n");
+ return -1;
+ }
+ addattr8(n, MAX_MSG, TCA_FLOWER_KEY_MPLS_BOS, bos);
+ } else if (matches(*argv, "mpls_ttl") == 0) {
+ __u8 ttl;
+
+ NEXT_ARG();
+ if (eth_type != htons(ETH_P_MPLS_UC) &&
+ eth_type != htons(ETH_P_MPLS_MC)) {
+ fprintf(stderr,
+ "Can't set \"mpls_ttl\" if ethertype isn't MPLS\n");
+ return -1;
+ }
+ ret = get_u8(&ttl, *argv, 10);
+ if (ret < 0 || ttl & ~(MPLS_LS_TTL_MASK >> MPLS_LS_TTL_SHIFT)) {
+ fprintf(stderr, "Illegal \"mpls_ttl\"\n");
+ return -1;
+ }
+ addattr8(n, MAX_MSG, TCA_FLOWER_KEY_MPLS_TTL, ttl);
} else if (matches(*argv, "dst_mac") == 0) {
NEXT_ARG();
ret = flower_parse_eth_addr(*argv,
fprintf(f, "/%d", mask);
}
+static void flower_print_u8(FILE *f, const char *name, struct rtattr *attr)
+{
+ flower_print_masked_u8(f, name, attr, NULL, NULL);
+}
+
+static void flower_print_u32(FILE *f, const char *name, struct rtattr *attr)
+{
+ __u32 value;
+
+ if (!attr)
+ return;
+
+ value = rta_getattr_u32(attr);
+
+ fprintf(f, "\n %s %d", name, value);
+}
+
static void flower_print_arp_op(FILE *f, const char *name,
struct rtattr *op_attr,
struct rtattr *mask_attr)
flower_print_ip_attr(f, "ip_ttl", tb[TCA_FLOWER_KEY_IP_TTL],
tb[TCA_FLOWER_KEY_IP_TTL_MASK]);
+ flower_print_u32(f, "mpls_label", tb[TCA_FLOWER_KEY_MPLS_LABEL]);
+ flower_print_u8(f, "mpls_tc", tb[TCA_FLOWER_KEY_MPLS_TC]);
+ flower_print_u8(f, "mpls_bos", tb[TCA_FLOWER_KEY_MPLS_BOS]);
+ flower_print_u8(f, "mpls_ttl", tb[TCA_FLOWER_KEY_MPLS_TTL]);
+
flower_print_ip_addr(f, "dst_ip", eth_type,
tb[TCA_FLOWER_KEY_IPV4_DST],
tb[TCA_FLOWER_KEY_IPV4_DST_MASK],