+/* Insert VLAN header according to given TCI. Packet passed must be Ethernet
+ * packet.
+ *
+ * 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;
+ tmp.veth_next_type = eh->eth_type;
+
+ veh = ofpbuf_push_uninit(packet, VLAN_HEADER_LEN);
+ memcpy(veh, &tmp, sizeof tmp);
+
+ packet->l2 = packet->data;
+}
+
+/* Given the IP netmask 'netmask', returns the number of bits of the IP address
+ * that it specifies, that is, the number of 1-bits in 'netmask'. 'netmask'
+ * must be a CIDR netmask (see ip_is_cidr()). */
+int
+ip_count_cidr_bits(ovs_be32 netmask)
+{
+ assert(ip_is_cidr(netmask));
+ return 32 - ctz(ntohl(netmask));
+}
+
+void
+ip_format_masked(ovs_be32 ip, ovs_be32 mask, struct ds *s)
+{
+ ds_put_format(s, IP_FMT, IP_ARGS(&ip));
+ if (mask != htonl(UINT32_MAX)) {
+ if (ip_is_cidr(mask)) {
+ ds_put_format(s, "/%d", ip_count_cidr_bits(mask));
+ } else {
+ ds_put_format(s, "/"IP_FMT, IP_ARGS(&mask));
+ }
+ }
+}
+
+