At least on my modem/router (Actiontec C1000A, BusyBox v1.17.2, kernel version 2.6.30), I was able to match directly on the destination IPv6 address using tc (i.e. no need for ip6tables to mark the packets):

tc class add dev eth0 parent 1:0 classid 1:14 htb rate 3000kbit ceil 3000kbit prio 3
tc filter add dev eth0 parent 1:0 protocol ipv6 prio 16 \
    u32 match ip6 dst $IPV6_ADDR flowid 1:14

So, it's a guess, but I should think the following would work:

tc filter add dev eth0 parent 1:0 protocol ipv6 prio 16 u32 match ip6 dport 80 flowid 1:14

Or, using your ip6tables mangling:

tc filter add dev eth0 parent 1:0 protocol ipv6 handle 14 fw flowid 1:14

Unfortunately tc does not work yet for IPv6.

Quote:

The Routing Policy Database (RPDB) replaced the IPv4 routing and addressing structure within the Linux Kernel which lead to all the wonderful features this HOWTO describes. Unfortunately, the IPv6 structure within Linux was implemented outside of this core structure. Although they do share some facilities, the essential RPDB structure does not particpate in or with the IPv6 addressing and routing structures.

This will change for sure, we just have to wait a little longer.

Source: http://lartc.org/lartc.html#AEN1446

If anyone knows if this is fixed from a certain kernel version on, or if there is a plan to fix this in a future version, feel free to update!

Possible workaround (not tested by myself so far) is to tunnel the IPv6 traffic (SIT tunnel) and filter on the IPv4 packets that contain the IPv6 packets.