.ti -8
.IR PUSH " := "
-.BR push " [ " protocol
+.RB "{ " push " | " mac_push " } [ " protocol
.IR MPLS_PROTO " ]"
.RB " [ " tc
.IR MPLS_TC " ] "
Decapsulation mode. Requires the protocol of the next header.
.TP
.B push
-Encapsulation mode. Requires at least the
+Encapsulation mode. Adds the MPLS header between the MAC and the network
+headers. Requires at least the
+.B label
+option.
+.TP
+.B mac_push
+Encapsulation mode. Adds the MPLS header before the MAC header. Requires at
+least the
.B label
option.
.TP
.EE
.RE
+Here is another example, where incoming Ethernet frames are encapsulated into
+MPLS with label 123 and TTL 64. Then, an outer Ethernet header is added and the
+resulting frame is finally sent on eth1:
+
+.RS
+.EX
+#tc qdisc add dev eth0 ingress
+#tc filter add dev eth0 ingress matchall \\
+ action mpls mac_push label 123 ttl 64 \\
+ action vlan push_eth \\
+ dst_mac 02:00:00:00:00:02 \\
+ src_mac 02:00:00:00:00:01 \\
+ action mirred egress redirect dev eth1
+.EE
+.RE
+
+The following example assumes that incoming MPLS packets with label 123
+transport Ethernet frames. The outer Ethernet and the MPLS headers are
+stripped, then the inner Ethernet frame is sent on eth1:
+
+.RS
+.EX
+#tc qdisc add dev eth0 ingress
+#tc filter add dev eth0 ingress protocol mpls_uc \\
+ flower mpls_label 123 mpls_bos 1 \\
+ action vlan pop_eth \\
+ action mpls pop protocol teb \\
+ action mirred egress redirect dev eth1
+.EE
+.RE
+
.SH SEE ALSO
-.BR tc (8)
+.BR tc "(8), " tc-mirred "(8), " tc-vlan (8)
[TCA_MPLS_ACT_PUSH] = "push",
[TCA_MPLS_ACT_MODIFY] = "modify",
[TCA_MPLS_ACT_DEC_TTL] = "dec_ttl",
+ [TCA_MPLS_ACT_MAC_PUSH] = "mac_push",
};
static void explain(void)
"Usage: mpls pop [ protocol MPLS_PROTO ]\n"
" mpls push [ protocol MPLS_PROTO ] [ label MPLS_LABEL ] [ tc MPLS_TC ]\n"
" [ ttl MPLS_TTL ] [ bos MPLS_BOS ] [CONTROL]\n"
+ " mpls mac_push [ protocol MPLS_PROTO ] [ label MPLS_LABEL ] [ tc MPLS_TC ]\n"
+ " [ ttl MPLS_TTL ] [ bos MPLS_BOS ] [CONTROL]\n"
" mpls modify [ label MPLS_LABEL ] [ tc MPLS_TC ] [ ttl MPLS_TTL ] [CONTROL]\n"
- " for pop MPLS_PROTO is next header of packet - e.g. ip or mpls_uc\n"
- " for push MPLS_PROTO is one of mpls_uc or mpls_mc\n"
+ " for pop, MPLS_PROTO is next header of packet - e.g. ip or mpls_uc\n"
+ " for push and mac_push, MPLS_PROTO is one of mpls_uc or mpls_mc\n"
" with default: mpls_uc\n"
" CONTROL := reclassify | pipe | drop | continue | pass |\n"
" goto chain <CHAIN_INDEX>\n");
static bool can_modify_mpls_fields(unsigned int action)
{
- return action == TCA_MPLS_ACT_PUSH || action == TCA_MPLS_ACT_MODIFY;
+ return action == TCA_MPLS_ACT_PUSH || action == TCA_MPLS_ACT_MAC_PUSH ||
+ action == TCA_MPLS_ACT_MODIFY;
}
-static bool can_modify_ethtype(unsigned int action)
+static bool can_set_ethtype(unsigned int action)
{
- return action == TCA_MPLS_ACT_PUSH || action == TCA_MPLS_ACT_POP;
+ return action == TCA_MPLS_ACT_PUSH || action == TCA_MPLS_ACT_MAC_PUSH ||
+ action == TCA_MPLS_ACT_POP;
}
static bool is_valid_label(__u32 label)
if (check_double_action(action, *argv))
return -1;
action = TCA_MPLS_ACT_PUSH;
+ } else if (matches(*argv, "mac_push") == 0) {
+ if (check_double_action(action, *argv))
+ return -1;
+ action = TCA_MPLS_ACT_MAC_PUSH;
} else if (matches(*argv, "modify") == 0) {
if (check_double_action(action, *argv))
return -1;
action = TCA_MPLS_ACT_DEC_TTL;
} else if (matches(*argv, "label") == 0) {
if (!can_modify_mpls_fields(action))
- invarg("only valid for push/modify", *argv);
+ invarg("only valid for push, mac_push and modify",
+ *argv);
NEXT_ARG();
if (get_u32(&label, *argv, 0) || !is_valid_label(label))
invarg("label must be <=0xFFFFF", *argv);
} else if (matches(*argv, "tc") == 0) {
if (!can_modify_mpls_fields(action))
- invarg("only valid for push/modify", *argv);
+ invarg("only valid for push, mac_push and modify",
+ *argv);
NEXT_ARG();
if (get_u8(&tc, *argv, 0) || (tc & ~0x7))
invarg("tc field is 3 bits max", *argv);
} else if (matches(*argv, "ttl") == 0) {
if (!can_modify_mpls_fields(action))
- invarg("only valid for push/modify", *argv);
+ invarg("only valid for push, mac_push and modify",
+ *argv);
NEXT_ARG();
if (get_u8(&ttl, *argv, 0) || !ttl)
invarg("ttl must be >0 and <=255", *argv);
} else if (matches(*argv, "bos") == 0) {
if (!can_modify_mpls_fields(action))
- invarg("only valid for push/modify", *argv);
+ invarg("only valid for push, mac_push and modify",
+ *argv);
NEXT_ARG();
if (get_u8(&bos, *argv, 0) || (bos & ~0x1))
invarg("bos must be 0 or 1", *argv);
} else if (matches(*argv, "protocol") == 0) {
- if (!can_modify_ethtype(action))
- invarg("only valid for push/pop", *argv);
+ if (!can_set_ethtype(action))
+ invarg("only valid for push, mac_push and pop",
+ *argv);
NEXT_ARG();
if (ll_proto_a2n(&proto, *argv))
invarg("protocol is invalid", *argv);
if (action == TCA_MPLS_ACT_PUSH && label == 0xffffffff)
missarg("label");
- if (action == TCA_MPLS_ACT_PUSH && proto &&
+ if ((action == TCA_MPLS_ACT_PUSH || action == TCA_MPLS_ACT_MAC_PUSH) &&
+ proto &&
proto != htons(ETH_P_MPLS_UC) && proto != htons(ETH_P_MPLS_MC)) {
fprintf(stderr,
- "invalid push protocol \"0x%04x\" - use mpls_(uc|mc)\n",
+ "invalid %spush protocol \"0x%04x\" - use mpls_(uc|mc)\n",
+ action == TCA_MPLS_ACT_MAC_PUSH ? "mac_" : "",
ntohs(proto));
return -1;
}
}
break;
case TCA_MPLS_ACT_PUSH:
+ case TCA_MPLS_ACT_MAC_PUSH:
if (tb[TCA_MPLS_PROTO]) {
__u16 proto;
--- /dev/null
+#!/bin/sh
+
+. lib/generic.sh
+
+DEV="$(rand_dev)"
+ts_ip "$0" "Add $DEV dummy interface" link add dev $DEV up type dummy
+ts_tc "$0" "Add ingress qdisc" qdisc add dev $DEV ingress
+
+reset_qdisc()
+{
+ ts_tc "$0" "Remove ingress qdisc" qdisc del dev $DEV ingress
+ ts_tc "$0" "Add ingress qdisc" qdisc add dev $DEV ingress
+}
+
+ts_tc "$0" "Add mpls action pop" \
+ filter add dev $DEV ingress protocol mpls_uc matchall \
+ action mpls pop protocol ip
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "mpls"
+test_on "pop protocol ip pipe"
+
+reset_qdisc
+ts_tc "$0" "Add mpls action push" \
+ filter add dev $DEV ingress protocol ip matchall \
+ action mpls push protocol mpls_uc label 20 tc 3 bos 1 ttl 64
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "mpls"
+test_on "push"
+test_on "protocol mpls_uc"
+test_on "label 20"
+test_on "tc 3"
+test_on "bos 1"
+test_on "ttl 64"
+test_on "pipe"
+
+reset_qdisc
+ts_tc "$0" "Add mpls action mac_push" \
+ filter add dev $DEV ingress matchall \
+ action mpls mac_push protocol mpls_uc label 20 tc 3 bos 1 ttl 64
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "mpls"
+test_on "mac_push"
+test_on "protocol mpls_uc"
+test_on "label 20"
+test_on "tc 3"
+test_on "bos 1"
+test_on "ttl 64"
+test_on "pipe"
+
+reset_qdisc
+ts_tc "$0" "Add mpls action modify" \
+ filter add dev $DEV ingress protocol mpls_uc matchall \
+ action mpls modify label 20 tc 3 ttl 64
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "mpls"
+test_on "modify"
+test_on "label 20"
+test_on "tc 3"
+test_on "ttl 64"
+test_on "pipe"
+
+reset_qdisc
+ts_tc "$0" "Add mpls action dec_ttl" \
+ filter add dev $DEV ingress protocol mpls_uc matchall \
+ action mpls dec_ttl
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "mpls"
+test_on "dec_ttl"
+test_on "pipe"