+ return ofpbuf_size(a) == ofpbuf_size(b) &&
+ memcmp(ofpbuf_data(a), ofpbuf_data(b), ofpbuf_size(a)) == 0;
+}
+
+/* Get the start if the Ethernet frame. 'l3_ofs' marks the end of the l2
+ * headers, so return NULL if it is not set. */
+static inline void * ofpbuf_l2(const struct ofpbuf *b)
+{
+ return (b->l3_ofs != UINT16_MAX) ? b->frame : NULL;
+}
+
+/* Sets the packet frame start pointer and resets all layer offsets.
+ * l3 offset must be set before 'l2' can be retrieved. */
+static inline void ofpbuf_set_frame(struct ofpbuf *b, void *packet)
+{
+ b->frame = packet;
+ b->l2_5_ofs = UINT16_MAX;
+ b->l3_ofs = UINT16_MAX;
+ b->l4_ofs = UINT16_MAX;
+}
+
+static inline void * ofpbuf_l2_5(const struct ofpbuf *b)
+{
+ return b->l2_5_ofs != UINT16_MAX ? (char *)b->frame + b->l2_5_ofs : NULL;
+}
+
+static inline void ofpbuf_set_l2_5(struct ofpbuf *b, void *l2_5)
+{
+ b->l2_5_ofs = l2_5 ? (char *)l2_5 - (char *)b->frame : UINT16_MAX;
+}
+
+static inline void * ofpbuf_l3(const struct ofpbuf *b)
+{
+ return b->l3_ofs != UINT16_MAX ? (char *)b->frame + b->l3_ofs : NULL;
+}
+
+static inline void ofpbuf_set_l3(struct ofpbuf *b, void *l3)
+{
+ b->l3_ofs = l3 ? (char *)l3 - (char *)b->frame : UINT16_MAX;
+}
+
+static inline void * ofpbuf_l4(const struct ofpbuf *b)
+{
+ return b->l4_ofs != UINT16_MAX ? (char *)b->frame + b->l4_ofs : NULL;
+}
+
+static inline void ofpbuf_set_l4(struct ofpbuf *b, void *l4)
+{
+ b->l4_ofs = l4 ? (char *)l4 - (char *)b->frame : UINT16_MAX;