+ memmove((char *)veh + VLAN_HEADER_LEN, veh, 2 * ETH_ADDR_LEN);
+ ofpbuf_resize_l2(packet, -VLAN_HEADER_LEN);
+ }
+}
+
+/* Set ethertype of the packet. */
+static void
+set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type)
+{
+ struct eth_header *eh = ofpbuf_l2(packet);
+
+ if (!eh) {
+ return;
+ }
+
+ if (eh->eth_type == htons(ETH_TYPE_VLAN)) {
+ ovs_be16 *p;
+ char *l2_5 = ofpbuf_l2_5(packet);
+
+ p = ALIGNED_CAST(ovs_be16 *,
+ (l2_5 ? l2_5 : (char *)ofpbuf_l3(packet)) - 2);
+ *p = eth_type;
+ } else {
+ eh->eth_type = eth_type;
+ }
+}
+
+static bool is_mpls(struct ofpbuf *packet)
+{
+ return packet->l2_5_ofs != UINT16_MAX;
+}
+
+/* Set time to live (TTL) of an MPLS label stack entry (LSE). */
+void
+set_mpls_lse_ttl(ovs_be32 *lse, uint8_t ttl)
+{
+ *lse &= ~htonl(MPLS_TTL_MASK);
+ *lse |= htonl((ttl << MPLS_TTL_SHIFT) & MPLS_TTL_MASK);
+}
+
+/* Set traffic class (TC) of an MPLS label stack entry (LSE). */
+void
+set_mpls_lse_tc(ovs_be32 *lse, uint8_t tc)
+{
+ *lse &= ~htonl(MPLS_TC_MASK);
+ *lse |= htonl((tc << MPLS_TC_SHIFT) & MPLS_TC_MASK);
+}
+
+/* Set label of an MPLS label stack entry (LSE). */
+void
+set_mpls_lse_label(ovs_be32 *lse, ovs_be32 label)
+{
+ *lse &= ~htonl(MPLS_LABEL_MASK);
+ *lse |= htonl((ntohl(label) << MPLS_LABEL_SHIFT) & MPLS_LABEL_MASK);
+}
+
+/* Set bottom of stack (BoS) bit of an MPLS label stack entry (LSE). */
+void
+set_mpls_lse_bos(ovs_be32 *lse, uint8_t bos)
+{
+ *lse &= ~htonl(MPLS_BOS_MASK);
+ *lse |= htonl((bos << MPLS_BOS_SHIFT) & MPLS_BOS_MASK);
+}
+
+/* Compose an MPLS label stack entry (LSE) from its components:
+ * label, traffic class (TC), time to live (TTL) and
+ * bottom of stack (BoS) bit. */
+ovs_be32
+set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos, ovs_be32 label)
+{
+ ovs_be32 lse = htonl(0);
+ set_mpls_lse_ttl(&lse, ttl);
+ set_mpls_lse_tc(&lse, tc);
+ set_mpls_lse_bos(&lse, bos);
+ set_mpls_lse_label(&lse, label);
+ return lse;
+}
+
+/* Set MPLS label stack entry to outermost MPLS header.*/
+void
+set_mpls_lse(struct ofpbuf *packet, ovs_be32 mpls_lse)
+{
+ /* Packet type should be MPLS to set label stack entry. */
+ if (is_mpls(packet)) {
+ struct mpls_hdr *mh = ofpbuf_l2_5(packet);
+
+ /* Update mpls label stack entry. */
+ put_16aligned_be32(&mh->mpls_lse, mpls_lse);
+ }
+}
+
+/* Push MPLS label stack entry 'lse' onto 'packet' as the the outermost MPLS
+ * header. If 'packet' does not already have any MPLS labels, then its
+ * Ethertype is changed to 'ethtype' (which must be an MPLS Ethertype). */
+void
+push_mpls(struct ofpbuf *packet, ovs_be16 ethtype, ovs_be32 lse)
+{
+ char * header;
+ size_t len;
+
+ if (!eth_type_mpls(ethtype)) {
+ return;
+ }
+
+ if (!is_mpls(packet)) {
+ /* Set MPLS label stack offset. */
+ packet->l2_5_ofs = packet->l3_ofs;
+ }
+
+ set_ethertype(packet, ethtype);
+
+ /* Push new MPLS shim header onto packet. */
+ len = packet->l2_5_ofs;
+ header = ofpbuf_resize_l2_5(packet, MPLS_HLEN);
+ memmove(header, header + MPLS_HLEN, len);
+ memcpy(header + len, &lse, sizeof lse);
+}