That was it! I can ping when I change the loopback addresses on the CE routers from /24 to /128. I thought I had tried this before, but I think I had some extra cabling issues at that time. I removed the "allow-v4mapped-packets" and "allow-6pe-traceroute" commands from every device, and I can still ping.
Here is the full red.inet6.0 table from both PE1 and PE2 when the CE loopbacks were /24:
root@PE1> show route table red.inet6.0
red.inet6.0: 5 destinations, 7 routes (5 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
::/24 *[BGP/170] 00:03:26, localpref 100
AS path: I, validation-state: unverified
> to ::10.1.1.1 via ge-0/0/0.0
[BGP/170] 00:01:02, localpref 100, from 192.0.2.4
AS path: I, validation-state: unverified
> to 10.1.1.6 via ge-0/0/1.0, Push 28, Push 299888(top)
::10.1.1.0/126 *[Direct/0] 00:19:25
> via ge-0/0/0.0
[BGP/170] 00:18:18, localpref 100
AS path: I, validation-state: unverified
> to ::10.1.1.1 via ge-0/0/0.0
::10.1.1.2/128 *[Local/0] 00:19:25
Local via ge-0/0/0.0
::10.1.1.12/126 *[BGP/170] 00:16:54, localpref 100, from 192.0.2.4
AS path: I, validation-state: unverified
> to 10.1.1.6 via ge-0/0/1.0, Push 28, Push 299888(top)
fe80::e36:47ff:fed4:a402/128
*[Local/0] 00:19:25
Local via ge-0/0/0.0
root@PE2> show route table red.inet6.0
red.inet6.0: 5 destinations, 7 routes (5 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
::/24 *[BGP/170] 00:01:56, localpref 100
AS path: I, validation-state: unverified
> to ::10.1.1.14 via ge-0/0/0.0
[BGP/170] 00:04:18, localpref 100, from 192.0.2.2
AS path: I, validation-state: unverified
> to 10.1.1.9 via ge-0/0/1.0, Push 300000, Push 299872(top)
::10.1.1.0/126 *[BGP/170] 00:17:47, localpref 100, from 192.0.2.2
AS path: I, validation-state: unverified
> to 10.1.1.9 via ge-0/0/1.0, Push 300000, Push 299872(top)
::10.1.1.12/126 *[Direct/0] 00:20:16
> via ge-0/0/0.0
[BGP/170] 00:19:46, localpref 100
AS path: I, validation-state: unverified
> to ::10.1.1.14 via ge-0/0/0.0
::10.1.1.13/128 *[Local/0] 00:20:16
Local via ge-0/0/0.0
fe80::e36:47ff:fef8:cd02/128
*[Local/0] 00:20:16
Local via ge-0/0/0.0
And here they are at /128:
root@PE1> show route table red.inet6.0
red.inet6.0: 6 destinations, 7 routes (6 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
::10.1.1.0/126 *[Direct/0] 00:52:33
> via ge-0/0/0.0
[BGP/170] 00:51:26, localpref 100
AS path: I, validation-state: unverified
> to ::10.1.1.1 via ge-0/0/0.0
::10.1.1.2/128 *[Local/0] 00:52:33
Local via ge-0/0/0.0
::10.1.1.12/126 *[BGP/170] 00:50:02, localpref 100, from 192.0.2.4
AS path: I, validation-state: unverified
> to 10.1.1.6 via ge-0/0/1.0, Push 28, Push 299888(top)
::192.0.2.1/128 *[BGP/170] 00:01:18, localpref 100
AS path: I, validation-state: unverified
> to ::10.1.1.1 via ge-0/0/0.0
::192.0.2.5/128 *[BGP/170] 00:01:04, localpref 100, from 192.0.2.4
AS path: I, validation-state: unverified
> to 10.1.1.6 via ge-0/0/1.0, Push 28, Push 299888(top)
fe80::e36:47ff:fed4:a402/128
*[Local/0] 00:52:33
Local via ge-0/0/0.0
root@PE2> show route table red.inet6.0
red.inet6.0: 6 destinations, 7 routes (6 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
::10.1.1.0/126 *[BGP/170] 00:50:42, localpref 100, from 192.0.2.2
AS path: I, validation-state: unverified
> to 10.1.1.9 via ge-0/0/1.0, Push 300000, Push 299872(top)
::10.1.1.12/126 *[Direct/0] 00:53:11
> via ge-0/0/0.0
[BGP/170] 00:52:41, localpref 100
AS path: I, validation-state: unverified
> to ::10.1.1.14 via ge-0/0/0.0
::10.1.1.13/128 *[Local/0] 00:53:11
Local via ge-0/0/0.0
::192.0.2.1/128 *[BGP/170] 00:01:57, localpref 100, from 192.0.2.2
AS path: I, validation-state: unverified
> to 10.1.1.9 via ge-0/0/1.0, Push 300000, Push 299872(top)
::192.0.2.5/128 *[BGP/170] 00:01:45, localpref 100
AS path: I, validation-state: unverified
> to ::10.1.1.14 via ge-0/0/0.0
fe80::e36:47ff:fef8:cd02/128
*[Local/0] 00:53:11
Local via ge-0/0/0.0
When they were at ::/24, I could see that the next-hop reference count was the main difference between the two ::/24 routes. I think this means that the best path was being selected based on the "Shortest IGP path to BGP next hop" BGP path-selection criteria. Here is the output I looked at to try to determine which BGP path-selection criteria was determining the tie-break between the two ::/24 routes:
root@PE2> show route table red.inet6.0 detail
red.inet6.0: 5 destinations, 7 routes (5 active, 0 holddown, 0 hidden)
::/24 (2 entries, 1 announced)
*BGP Preference: 170/-101
Next hop type: Indirect, Next hop index: 0
Address: 0xb6754b0
Next-hop reference count: 4
Source: ::10.1.1.14
Next hop type: Router, Next hop index: 614
Next hop: ::10.1.1.14 via ge-0/0/0.0, selected
Session Id: 0x15b
Protocol next hop: ::10.1.1.14
Indirect next hop: 0xbdda080 1048574 INH Session ID: 0x15c
State: <Active Int Ext>
Local AS: 64510 Peer AS: 64510
Age: 26:33 Metric2: 0
Validation State: unverified
Task: BGP_64510_64510.::10.1.1.14
Announcement bits (3): 0-KRT 1-BGP_RT_Background 2-Resolve tree 3
AS path: I
Accepted
Localpref: 100
Router ID: 192.0.2.5
BGP Preference: 170/-101
Route Distinguisher: 64512:1
Next hop type: Indirect, Next hop index: 0
Address: 0xb676590
Next-hop reference count: 5
Source: 192.0.2.2
Next hop type: Router, Next hop index: 620
Next hop: 10.1.1.9 via ge-0/0/1.0, selected
Label operation: Push 300000, Push 299872(top)
Label TTL action: prop-ttl, prop-ttl(top)
Load balance label: Label 300000: None; Label 299872: None;
Label element ptr: 0xced0080
Label parent element ptr: 0xb676fa0
Label element references: 1
Label element child references: 0
Label element lsp id: 0
Session Id: 0x15d
Protocol next hop: ::ffff:192.0.2.2
Label operation: Push 300000
Label TTL action: prop-ttl
Load balance label: Label 300000: None;
Indirect next hop: 0xbddae00 1048576 INH Session ID: 0x15f
State: <Secondary NotBest Int Ext ProtectionCand>
Inactive reason: Not Best in its group - IGP metric
Local AS: 64512 Peer AS: 64512
Age: 28:55 Metric2: 1
Validation State: unverified
Task: BGP_64512.192.0.2.2
AS path: I
Import Accepted
VPN Label: 300000
Localpref: 100
Router ID: 192.0.2.2
Primary Routing Table bgp.l3vpn-inet6.0
I am far from 100% sure that IGP metric is what determined which ::/24 to make active.