+ eth->eth_type = htons(ETH_TYPE_RARP);
+
+ arp = ofpbuf_put_uninit(b, sizeof *arp);
+ arp->ar_hrd = htons(ARP_HRD_ETHERNET);
+ arp->ar_pro = htons(ARP_PRO_IP);
+ arp->ar_hln = sizeof arp->ar_sha;
+ arp->ar_pln = sizeof arp->ar_spa;
+ arp->ar_op = htons(ARP_OP_RARP);
+ memcpy(arp->ar_sha, eth_src, ETH_ADDR_LEN);
+ put_16aligned_be32(&arp->ar_spa, htonl(0));
+ memcpy(arp->ar_tha, eth_src, ETH_ADDR_LEN);
+ put_16aligned_be32(&arp->ar_tpa, htonl(0));
+}
+
+/* Insert VLAN header according to given TCI. Packet passed must be Ethernet
+ * packet. Ignores the CFI bit of 'tci' using 0 instead.
+ *
+ * Also sets 'packet->l2' to point to the new Ethernet header. */
+void
+eth_push_vlan(struct ofpbuf *packet, ovs_be16 tci)
+{
+ struct eth_header *eh = packet->data;
+ struct vlan_eth_header *veh;
+
+ /* Insert new 802.1Q header. */
+ struct vlan_eth_header tmp;
+ memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN);
+ memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN);
+ tmp.veth_type = htons(ETH_TYPE_VLAN);
+ tmp.veth_tci = tci & htons(~VLAN_CFI);
+ tmp.veth_next_type = eh->eth_type;
+
+ veh = ofpbuf_push_uninit(packet, VLAN_HEADER_LEN);
+ memcpy(veh, &tmp, sizeof tmp);
+
+ packet->l2 = packet->data;
+}
+
+/* Removes outermost VLAN header (if any is present) from 'packet'.
+ *
+ * 'packet->l2_5' should initially point to 'packet''s outer-most MPLS header
+ * or may be NULL if there are no MPLS headers. */
+void
+eth_pop_vlan(struct ofpbuf *packet)
+{
+ struct vlan_eth_header *veh = packet->l2;
+ if (packet->size >= sizeof *veh
+ && veh->veth_type == htons(ETH_TYPE_VLAN)) {
+ struct eth_header tmp;
+
+ memcpy(tmp.eth_dst, veh->veth_dst, ETH_ADDR_LEN);
+ memcpy(tmp.eth_src, veh->veth_src, ETH_ADDR_LEN);
+ tmp.eth_type = veh->veth_next_type;
+
+ ofpbuf_pull(packet, VLAN_HEADER_LEN);
+ packet->l2 = (char*)packet->l2 + VLAN_HEADER_LEN;
+ memcpy(packet->data, &tmp, sizeof tmp);
+ }
+}
+
+/* Set ethertype of the packet. */
+void
+set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type)
+{
+ struct eth_header *eh = packet->data;
+
+ if (eh->eth_type == htons(ETH_TYPE_VLAN)) {
+ ovs_be16 *p;
+ p = ALIGNED_CAST(ovs_be16 *,
+ (char *)(packet->l2_5 ? packet->l2_5 : packet->l3) - 2);
+ *p = eth_type;
+ } else {
+ eh->eth_type = eth_type;
+ }
+}
+
+static bool is_mpls(struct ofpbuf *packet)
+{
+ return packet->l2_5 != NULL;
+}
+
+/* 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;
+}
+
+/* Push an new MPLS stack entry onto the MPLS stack and adjust 'packet->l2' and
+ * 'packet->l2_5' accordingly. The new entry will be the outermost entry on
+ * the stack.
+ *
+ * Previous to calling this function, 'packet->l2_5' must be set; if the MPLS
+ * label to be pushed will be the first label in 'packet', then it should be
+ * the same as 'packet->l3'. */
+static void
+push_mpls_lse(struct ofpbuf *packet, struct mpls_hdr *mh)
+{
+ char * header;
+ size_t len;
+ header = ofpbuf_push_uninit(packet, MPLS_HLEN);
+ len = (char *)packet->l2_5 - (char *)packet->l2;
+ memmove(header, packet->l2, len);
+ memcpy(header + len, mh, sizeof *mh);
+ packet->l2 = (char*)packet->l2 - MPLS_HLEN;
+ packet->l2_5 = (char*)packet->l2_5 - MPLS_HLEN;
+}