Yes, the connection mark is present on all packets of a connection - and connections are bidirectional and include upstream and downstream traffic.
Connection marks work with all connections that are recognized as stateful. That includes all TCP and the vast majority of UDP and ICMP (basically everything that is bidirectional, and within the timing parameters of the limits set in "/ip firewall connection-tracking").
For performance, to me it breaks down like this: if you only need to do one thing to a packet and can recognize it very easily by one comparison (e.g. just the source address, or the in-interface) you might as well just apply the marks to the packet directly and not mark the connection. Whether I'm comparing the incoming interface or the connection mark for each packet is irrelevant.
When you're comparing more than just one property or need to change several things on a packet (e.g. apply a packet mark, a routing mark, change DSCP and TTL) it's better to just go off the connection mark. Also, ensure you limit the rule that sets the connection mark via "connection-mark=no-mark"- otherwise you're remarking the connection with EVERY packet of the connection, which kills all the performance gains you might otherwise see.
Below some code.
This applies a connection mark based on just one parameter and then sets a packet mark based on the connection mark:
/ip firewall mangle
add chain=prerouting in-interface=LAN1 action=mark-connection new-connection-mark=myMark passthrough=yes
add chain=prerouting connection-mark=from_LAN1 action=mark-packet new-packet-mark=myMark passthrough=no
That is wasteful to me - the below does the same thing in one fewer rule, and compares just as many parameters:
/ip firewall mangle
add chain=prerouting in-interface=LAN1 action=mark-packet new-packet-mark=myMark passthrough=no
The below works without connection marks and has to compare four packet parameters for each packet:
/ip firewall mangle
add chain=prerouting src-address=10.1.0.0/24 dst-address=10.2.0.0/24 protocol=tcp dst-port=80 action=mark-packet new-packet-mark=myMark passthrough=no
That's relatively expensive to do. The adjusted below version applies a connection mark based on several parameters that have to be compared, and only does so for connections that don't have a mark yet (so one packet per connection), and then all subsequent packets can be marked based on just one comparison. However, each packet still has to first be determined to not have a connection mark yet and will be checked against the first rule until it doesn't match:
/ip firewall mangle
add chain=prerouting connection-mark=no-mark src-address=10.1.0.0/24 dst-address=10.2.0.0/24 protocol=tcp dst-port=80 action=mark-connection new-connection-mark=myMark passthrough=yes
add chain=prerouting connection-mark=myMark action=mark-packet new-packet-mark=myMark passthrough=no
Here's where I have a question for the devs: is the 'connection-mark=no-mark' condition always evaluated first among checks for a packet, and does the comparison process then immediately jump out of that rule by short circuit logic?
Or does each packet get evaluated against ALL of the the comparisons, or some of them because they get evaluated by the code before the connection mark is? I'd imagine it's short circuit logic, but would like to know if connection marks always get checked first. If they aren't and, for example, are evaluated after source and destination addresses but before protocol and port then the above would still check every single packet of a flow against three comparisons (source address, destination address, then connection state that doesn't match and the rule doesn't fire) before going to the second rule that then marks the packet. That would lead to a total of four comparisons before a packet mark is applied (source and destination address and connection mark in the first rule, connection mark in the second rule), which isn't more efficient to do than the original version without connection marks.
Though I guess you could ensure to optimize processing speed like below where packets that have a connection mark are immediately marked and then bail out via passthrough=no, and then mark connections on remaining packets (first packets of the connections), and then apply the same rule again to finally mark that first packet:
/ip firewall mangle
add chain=prerouting connection-mark=myMark action=mark-packet new-packet-mark=myMark passthrough=no
add chain=prerouting connection-mark=no-mark src-address=10.1.0.0/24 dst-address=10.2.0.0/24 protocol=tcp dst-port=80 action=mark-connection new-connection-mark=myMark passthrough=yes
add chain=prerouting connection-mark=myMark action=mark-packet new-packet-mark=myMark passthrough=no
That way packets in a connection that have been marked require always just one comparison before the packets themselves can be marked. Or is there a more optimal way to write that ruleset?