Sounds to me like you'll need to do a layering.
When you have nested packets, I prefer to create separate objects, something like (pseudocode):
class encap_pkt extends uvm_sequence_item;
class my_pkt extends uvm_sequence_item;
You can randomize the length of the encap_pkt::pkt array if you wish, and you can randomize the length/content of the my_pkt::payld field (and anything else you want). Then you use the layering to create the encap_pkt packets at the top level and translate those into my_pkt packets at the lower level.
I wouldn't think you'd need to worry about pack/unpack since ultimately the driver at the lowest level would know what the structure of the packet is that it gets and could manipulate the data accordingly.