Symmetry property of fair and efficient wage taxation

2017 January 13
by Daniel Lakeland

Based on my discussion of eating your own labor one of the major points there is that the second earner in a household faces a massive tax burden that makes it generally unwise for households to have two earners unless each of them earns a very low wage. What would be a better scheme? Really we'd like two people in a household to face symmetric work incentives. This then enables households where two people have advanced degrees or other large earning potential to both do the thing that society most wants them to be doing (namely, working to provide valuable services).

This symmetry property works as follows. Suppose we have worker W1 and W2, and they earn salaries S1 and S2. We can define a function Keep(S) that describes how much of the salary a single worker keeps.

Keep(S) = \int_0^S (1-t(x))dx

Where t(x) is the marginal tax on an extra dollar that a person earning x dollars takes home.

Now, the symmetry property we want is

Keep_2(S1+S2) = Keep(S1) + Keep(S2)

That is, whether you aggregate the salaries into a single household and use the household keep function, or you consider them split out as two totally separate earners, you still get the same total amount kept by the two earners.

Now, this is something like linearity. The property of linearity would be

Keep_2 = Keep


Keep(a\times S) = a\times Keep(S)


Keep(S1 + S2) = Keep(S1) + Keep(S2)

But, our fairness/symmetry requirement imposes a weaker requirement than linearity. For example suppose Keep_2(x) = x for x < 2 and Keep_2(x) = 2 for x > 2, and Keep(x) = x for  x< 1 and Keep(x) = 1 for x > 1, (that is, you keep 100% of the first dollar each person earns and nothing after that). Then the symmetry we want holds, but of course this is a seriously pathological example.
Now let's examine a further principal. The idea is you should keep SOME of every dollar that you earn, otherwise there is no incentive to do something valuable to society for which you can get paid, since the pay would all go to the government. This principal can be translated to the following mathematics:

\forall x \ge 0, \frac{dKeep}{dx} > 0

Which says that the Keep function is always going up at least a little bit.These two principals are sufficient to show that both the Keep and the Keep_2 functions are lines with the same slope. We can do this by supposing that S1 is anything you like, and S2 is $1 which we will take to be dx, an essentially infinitesimal quantity.

Keep_2(S1+S2) = Keep_2(S1) + \left. \frac{dKeep_2}{dx}\right |_{S1} dx \\= Keep(S1) + Keep(S2) = Keep(S1) + \left. \frac{dKeep}{dx}\right |_0 dx

Which shows that Keep_2(S1) = Keep(S1) and \left. \frac{dKeep_2}{dx}\right |_{S1} = \left. \frac{dKeep}{dx}\right |_0, which is to say that the Keep and the Keep_2 function are the same, and they have the same slope at any arbitrary point S1 as they do at x=0 (so it's a line).

You can also get that the keep functions are the same from Keep_2(S1+0) = Keep(S1) + Keep(0) and Keep(0)=0.

From this, I argue, the only income/wage tax compatible with the family value of "not punishing a second earner in a married household" is a flat tax on wages (ie. a constant tax rate, you're always taxed say p% of your total earnings). In my opinion, Feminists should be arguing strongly for flat taxation as women are more likely to be second earners, and women, particularly women who are educated, have student loans, have deferred incomes to gain skills, and soforth are the ones most harmed by wage taxes with increasing rates for increasing household income.

Furthermore, society needs the skills of all the highly skilled people we can get. Highly skilled people tend to marry other highly skilled people. We can't afford to be educating anyone to get skills and then leave them unable to take advantage of those skills because they're the second earner in a high earning household. That means we either give up on highly skilled people having families (completely untenable!), or we give up the value to society they would have provided in services if their marginal tax rates were constant, and make them pay for their student loans from their spouses salaries instead of what would have been their high earning potential.

Note: those who complain about the "regressive" nature of flat taxes should defer their complaints. The amount you consume doesn't need to be equal to the wages you keep. You can also spend money you receive from the government or from non-wage sources, and I will argue for a Universal Basic Income to compliment flat taxation in a future post. Furthermore, it's entirely plausible that the harm to society from making half the potential skilled work-force stay out of work is plausibly much larger than any harm from regressive taxation.


On taxes, wages, and eating your own labor

2017 January 13
by Daniel Lakeland

In Los Angeles, a middle class family of 4 can eat out at a restaurant for around $50 (likely a little more if you are eating only relatively healthy food).

In a month eating out every meal, you would spend: $50x3x30 = $4500/mo

Now, shopping for groceries for a family of 4 costs about $900/mo. Cooking for a family of 4 takes about 3 hours a day including washing up. This is an hourly "after tax wage" of $(4500-900)/(3*30) = $40/hr, and a monthly "after tax earnings" of 4500-900 = $3600/mo.

A family with one wage earner with an upper middle class job (8 hour days + commute and earning $75,000/yr before taxes), and one stay at home parent has a marginal tax rate (in LA) of about 25% federal + 9% SS&Medicare + 6% CA state = 40%, this could go up to around 50% for upper-middle class incomes. (let's not forget the employer part of the SS&M but it doesn't enter this calculation)

So, to earn $3600/mo take-home the second worker in the family needs before tax income of $3600/(1-.4) = $6000, or $72,000/yr. How many jobs are there where you can work 3 hours a day and earn $72,000/yr ? The GDP/capita is $56,000, and median household income is also about $56,000 and most wage earners give up more than 8 hours a day (esp. including commute, and for those earning $75k as salaried workers let's face it, 8 hr days are the minimum).

And this is just comparing cooking your own food to eating out at restaurants. Hiring someone to come and do laundry and clean a house twice a week costs easily $500/mo, which before taxes would be 500/.6 = $833/mo or $10k/yr. So, cooking and cleaning for a family of 4 for say 4 hours a day vs 8-10 hour days with a salary of $82,000  and by the way you'll wind up financially breaking even?

Hmmmmm, and people wonder why there's so much economic anxiety and so many Men Without Work? As more women get career jobs, it will become more and more common for husbands to stay home, why would they go to work when that would mean losing both time and money?


Did my little piece for good science and engineering today

2016 December 16
by Daniel Lakeland

I had a call from a client who is dealing with a quality control issue in the repair and re-installation of a large number of windows at a hotel. My recommendation came down to the only way to ensure consistency through time in installation was to randomly test as things were repaired. In particular, no you can't say that there were 200 windows installed in the last few months, but only 20 of them were eligible for testing on the day you went out, and of the 20, 7 were randomly selected for testing, and all of the 7 passed, and then extrapolate to what the condition of the full 1000 windows will be at the end of the project a year from now.

Unlike a random number generator whose consistency is mathematically guaranteed by algorithm design and testing, in the real world windows are installed through time, in different temperatures, different amounts of rain, with materials coming from different suppliers, with crews that get sick, or have vacations, with materials that are delivered and sit out in the sun, or don't sit out the sun, with windows installed on different faces of the building getting different amounts of heat, or wind, different amounts of dust on the surfaces that the sealant has to adhere to, different crews who do or do not know about how to properly clean the surfaces...

Unlike a computer RNG there is no future guarantee of consistency in real-world conditions.

I also argued for choosing how much resources to allocate to testing by balancing the cost of testing against the expected risk cost of having to re-repair windows done wrong, rather than say relying on some formal NHST power calculation or the like (these questions typically come in the form "how many windows would we have to test to have 95% confidence?" which isn't a complete question, but even if you flesh it out so that it has an answer, it's still the wrong way to think about the problem.). I find it makes sense to reorienting the question towards something like: "what is the best number of windows to test to keep our total cost low including the cost of both testing, and of re-repairing things when we later discover they were done wrong?"

Fortunately, Engineers tend to find Bayesian interpretations of probability and cost optimization methods intuitive and appealing.


Social Science At Work

2016 December 13
by Daniel Lakeland



Getting multiple /64 prefixes from ATT NVG599

2016 December 6
by Daniel Lakeland

So, it turns out that the NVG599 doesn't seem to hand out big prefixes like /60 or /61 but it will hand out several individual /64 prefixes.

So, now I have full native speed ipv6, with up to 15 prefixes for internal networks (the 16th is for the WAN side network that the ATT router "owns")

Example config in wide-dhcpv6, if you have WAN on eth0 and LAN on eth1 and you want eth1.10 vlan to have its own prefix.

The line "ia-pd 0" and "ia-pd 1" define two requests for prefixes


# Default dhpc6c configuration: it assumes the address is autoconfigured using
# router advertisements.

profile default

  request domain-name-servers;
  request domain-name;

  script "/etc/wide-dhcpv6/dhcp6c-script";

interface eth0 {
    send rapid-commit;

    send ia-na 0;
    send ia-pd 0; ## request our main prefix
    send ia-pd 1; ## request a second prefix

id-assoc na 0 {
## puts an address on the wan side eth0

## define the prefix we want for our main prefix
id-assoc pd 0 {
    prefix ::/64 infinity;

    # Internal interface (LAN)
    prefix-interface eth1 {
        sla-len 0;
        sla-id 1;
        ifid 1;

## define the prefix we want for our second one
id-assoc pd 1 {
    prefix ::/64 infinity;

    # Internal interface (LAN)
    prefix-interface eth1.10 {
        sla-len 0;
        sla-id 1;
        ifid 1;


Getting an IPv6 /60 Prefix with ATT 6rd tunnels

2016 December 1
by Daniel Lakeland

EDIT: although the below system WORKS, it gave me ABYSMAL performance. On my gigabit connection I was getting ~500Mbps over ipv4 and around 20Mbps over the ipv6 tunnel set up this way (test your ipv4/6 speeds at Comcast's Speed Test which tests both types of connections). Going back to getting my ipv6 from ATT's router gave me full speed ipv6. Evidently there's some traffic shaping on the ATT side that doesn't apply to my Arris router. DON'T set up the following unless you need more subnets more than you need full speed.

So, the router supplied by ATT was an Arris NVG599, it has 6rd set up by default. ATT is set up with its own 6rd /28 prefix such that by appending your DHCPv4 address you can get a /60 prefix. The Arris router supplied will delegate exactly one of the 16 /64 prefixes to your machine via a DHCPv6 request, which you can get wide-dhcp-client to do for you. This of course is fine if you just want a single /64 but what if you want something like a guest wifi VLAN with its own ipv6 prefix? You have a /60 available to you, but how to make it work?

First off, go to the firewall settings on the Arris box and under ip passthrough mode turn on passthrough with DHCPS-fixed, and choose your Linux router box as the machine to receive the public IP.

Now, turn OFF the ipv6 services on the Arris under "Home Network". Restart the Arris box and the router so you get fresh DHCPv4 address on your router.

Now, you're running a Debian based system of course 😉 so you'll want to set up a 6rd tunnel, get yourself a /60 prefix, and then manually delegate one of those prefixes to your LAN interface. You can potentially manually delegate additional prefixes to VLANs or other interfaces on your router box as well. Here's how:

Make sure you've installed ipv6calc

apt-get install ipv6calc

In /etc/network/interfaces

auto tun6rd
iface tun6rd inet manual
      up /etc/network/6rdup
      down ip tunnel del tun6rd

Now, you need the script /etc/network/6rdup, mine looks like:

#!/bin/bash -x

PUBLICIP=$(ip addr show $PUBLICIFACE | sed -n -E -e "/(192.168)/! s: *inet ([0-9.]*)/.*:\1:p")

OUR6RD=$(ipv6calc -q --action 6rd_local_prefix --6rd_prefix ${ATT6RDPREF} ${PUBLICIP} | sed -e "s/::/::1/")

OURDELEGATE1=$(echo $OUR6RD | sed -e "s|.::.*|1::1/64|")

MTU=1472 ## it's what the router uses

echo ${PUBLICIP}

echo "IP Tunnel: ${OUR6RD} via tun6rd"

ip tunnel add tun6rd mode sit local ${PUBLICIP} ttl 64
ip tunnel 6rd dev tun6rd 6rd-prefix ${ATT6RDPREF}
ip addr add ${OUR6RD} dev tun6rd
ip link set tun6rd up
ip link set dev tun6rd mtu $MTU
ip route add ::/0 via ::${ATT6RDRELAY} dev tun6rd

ip addr add ${OURDELEGATE1} dev $OURLANIFACE
exit 0 ## do more error checking if you like


Your mileage may vary, and you may need to debug this stuff. In particular, I'm not doing much error checking, and I'm not removing the ipv6 address from the internal interface when the link comes down. Bringing links up and down several times on your router might cause trouble. Either fix that or just do a reboot instead of monkeying with indidivual interfaces (after all, you want to make sure you can restart the thing and get a properly working network).

With this all in place, together with dnsmasq to handle router advertising and do DHCP/DHCPv6 on my local lan, and Firehol to handle the firewall, I get a fully routed ipv6 subnet on my lan with firewall that passes only very limited inbound traffic, and full outbound traffic... with no appreciable change in latency. The 6rd relay is an ATT anycast ipv4 address so it picks out the "closest" ipv4 relay for you to use. In my case "ping6" has a 9-10ms round trip for example.

IPv6 ULA for redundancy

2016 November 30
by Daniel Lakeland

The IPv6 standard has a concept called ULA (Unique Local Address) similar in nature to the or address spaces in IPv4. For IPv6 these are in the address space fc00::/7. They are addresses that are defined only locally within an organization and don't route on the wide internet. In general, it seems like these addresses are a bad idea to use reflexively. But what are some actual use cases?

One that I can think of is to deal with the 6rd addresses typically handed out by consumer ISPs. The way these work is that each ISP has a prefix, and then your router creates a sub-prefix by taking the ISP prefix and appending your dynamic IPv4 address. If the ISP prefix is short enough, you can have a few bits of address space to play with for yourself. A 6rd prefix looks like


Well, as you can probably guess, every time your power goes out for a couple of hours you might lose your IPv4 DHCP lease and now your whole network needs to be renumbered when you come back up with a new ipv6 prefix.

Ideally, when you sign up with your ISP, they'd give you a fixed static IPv6 /56 or even /48 prefix, which you would keep until you decide to move to a different ISP, but instead of that administrative hassle, they've invented a way to use the existing IPv4 DHCP infrastructure, which makes their lives easier, but your life less certain.

Sure, responding to new prefixes is do-able. But also, what about ISP outages? Just because your ISP goes down when a squirrel chews through your connection, doesn't mean you want to lose access to say your printer or scanner or file-share within your home or small business (ok, sure you've got an ipv4 set up anyway... but honestly that won't be forever).

Enter the ULA. You create a random prefix in the ULA space (get one randomly generated here) and then you set this up as an additional prefix for your local network. Now you can provide your laser printer or Samba share or web/security camera with a static local address that doesn't depend on what your ISP (or the squirrels!) had for breakfast, and your other hosts can auto-configure via SLAAC so that they can access these printers/cameras/shares via the ULA prefix.

If you're big enough to have your own assigned IPv6 prefix, then great, you can use those numbers, but if your ISP is someone like ATT who is using 6rd and your IPv6 prefix is inevitably going to depend on some IPv4 DHCP lease that is totally unpredictable, then ULA can give you a predictable redundant local network that always looks the same regardless of what happens on the wide internet. That's a good thing for the majority of us.


QoS Throttling Netflix and YouTube

2016 November 25
by Daniel Lakeland

If you look on the internet there are lots of professional network people, especially at Colleges and Universities, who are trying to limit the bad effects of people streaming movies on their network. Netflix in particular is very popular and takes up to around 3GB/hour of streaming HD video (~ 7 Mbps). Even a regular SD video might take 1 GB/hr (2.2 Mbps). A few hundred students all lounging around between classes could consume a full gigabit/s internet connection.

But, how to do it? If you have a smallish network with a single uplink point, it's not too hard. A combination of dnsmasq, Firehol, and FireQOS on your router together with the Linux ipset functionality can both prioritize the video streams so that they don't stutter, and at the same time limit the total bandwidth so that other activities don't suffer. Netflix, and YouTube with broad content delivery networks, can both easily hit 200 or more Mbps for 3 seconds while buffering up HD videos. That's 3 seconds of drop-out or stuttering on your VOIP call or lock-up in your interactive game. Those high peaks of bandwidth usage can saturate WiFi connections, make interactive games or voice communications break down and generally cause problems. Forcing these streams to buffer for a longer time at lower peak bandwidth means plenty of room for small interactive packets to interleave. Solving this issue is a good way to improve interactivity and voice quality. Here's how:


  • You have a Linux machine as a router, either a commercial dedicated wifi-router with OpenWRT or a small Intel based server, such as a Mini-ITX or even a regular desktop machine with several NICs.
  • You have dnsmasq, Firehol and Fireqos installed, as well as ipset and all associated required packages ("apt-get install firehol fireqos dnsmasq ipset" on Debian).
  • You have configured your network so the computers using it get their ipv4 addresses from dnsmasq via DHCP, and also use dnsmasq as the local nameserver, so all the machines on your network ask dnsmasq on your router when they need names resolved.

There is a feature of dnsmasq which will add the looked-up IP addresses to an ipset if the name comes from a particular domain. To use this feature we'll create two ipsets (one for IPv6 one for IPv4) to hold addresses from the domains (from which YouTube gets its video content) and (where Netflix serves its video), add the following lines to dnsmasq.conf


To create the ipsets we'll use Firehol, and then we'll use Firehol to mark packets adding something like this to the config before the first interface definition:

ipset4 create videostream4 hash:ip
ipset6 create videostream6 hash:ip

## kill off the DSCP mark inbound, don't trust others to classify our packets

#mark my voice packets high priority

#mark video packets medium priority using AF41
dscp6 class AF41 PREROUTING src6 ipset:videostream6
dscp4 class AF41 PREROUTING src4 ipset:videostream4

We've marked packets from these video streaming sources with dscp mark AF41 (decimal value 34). This is the highest "assured forwarding" class, with low drop probability. It's recommended for use with Live Video by Cisco. My assumption here is that your spouse will not like it if video stutters thanks to your messing around on the router. The voice packets get an even higher DSCP=48 priority which ensures WiFi WMM puts them in the VOICE queue.

Finally, we'll use FireQOS to give these packets a moderate high priority but limit them to some total bandwidth. Typically maybe 4 HD streams would be enough for a single family, so around 27 Mbps would be reasonable, with some overhead required, maybe 33 Mbps would make sense.

Note, both Netflix and YouTube are modern infrastructure with plenty of IPv6 connectivity, so you will need to use an "interface46" declaration in FireQOS to prioritize BOTH types of IP packets. I have a bonded interface "bond0" that is my LAN output. In FireQOS I have QOS on the LAN side output:

interface46 bond0 lanout output rate 2500Mbit qdisc fq_codel minrate 1mbit
    class voicertp commit 1mbit ceil 10mbit
        match4 udp src MY_ASTERISK_BOX
    class video commit 1mbit ceil 33mbit
        match dscp AF41

In addition to this causing routed video stream traffic to be limited to 33mbit it also puts a dscp AF41 mark on the packet which causes it to have reasonably high priority over WiFi (the VI queue intended for video use) under the WMM QoS system in 802.11n and later, so downstream on your network it will also be treated as an important but not top-priority packet.

That's it! Using "fireqos status lanout" you can watch as packets go through the video class at maximum 33mbps instead of the default class at 250mbps or whatever, leaving you with plenty of spare bandwidth for interactivity over a typical WiFi connection.


Typical Nerd Network?

2016 November 20
by Daniel Lakeland

So, I'm not sure how typical this is for people who actually use computers for work and such, but this is more or less how my home network looks. With my main workstation taking files off the home server via NFS, it seemed like a good idea to split the server and printer off from the Buffalo WiFi "router" (no longer routing, just a fancy AP) and the ATA so that all the calls will be going over a separate cable from any filesystem operations.

Once gigabit fiber WAN hit, I needed to move the routing load from the little Buffalo router to the home server, which is when I added a "Smart Managed" switch. Doing that also lets me prioritize voice packets via DSCP on the local LAN so if I'm doing something like talking on the phone while browsing PDF scans of documents, the traffic to my computer reading images off the server doesn't interfere with my calls.

The home server runs on an Asrock Rack J1900D2Y which is a mini-itx motherboard with a dedicated IPMI port (shown in red). The switch also lets me prioritize IPMI traffic (slightly lower than the voice traffic but higher than default traffic) so that if something goes wrong and I need to reboot the server I can connect without lag. The server is headless and has no keyboard.

I discovered that the IPMI port on these (and also on Supermicro mobos) can failover to be shared with the first ethernet port on the motherboard. This causes no end of trouble when the IPMI traffic starts appearing on one of the links in the bonded LAG group. It seemed like the solution would be to force the IPMI to only use the dedicated port, but I haven't yet figured out how to make that actually happen (altering it in the IPMI network settings didn't seem to work, I think I need to get into the BIOS but that requires a reboot of the server while using IPMI and then I have been losing my IPMI connection and can't see the BIOS screen because it tries to failover during boot). A reasonable solution was to statically allocate the IPMI MAC address to the port where the dedicated IPMI link goes into the managed switch. At least then the switch doesn't start getting confused about the LAG group, and the IPMI port eventually figures out that it can't talk to anyone on its failover port so it sticks to Dedicated.

Yellow links show battery-backed UPS power, so I can still have internet access and phone calls for several tens of minutes to an hour after power goes out. That duration was much longer when the whole thing was routed by the Buffalo device, but it's still a reasonable amount of time since the little Mini-ITX server, switch, and RAID enclosure all use about 8% of the max UPS output, or something like 75 watts.

I'm pretty sure this system could handle a full office for a medium business of around 100 people with just the addition of a couple of POE switches and some desk phones (and a whole lot more floor space!). For a system like that I'd probably move the file server function to a cluster of two servers running glusterfs to handle hardware failures and planned downtime more smoothly.

As it is right now the whole thing works pretty smoothly and gives me a place to store large files and archive lots of photos without having my important files connected directly to my desktop machine where I run more bleeding edge kernels and occasionally run large computations that have a chance of accidentally filling all the RAM and bringing the machine to its knees (there was some particularly nasty issue trying to plot some of my recent graphs. I think ggplot was making a full copy of a large data frame once for each plot in a spaghetti plot, leading to 65GB RAM usage... moving to data.tables helped a lot, and also re-thinking how the plot was constructed so that it was using just one copy of the table).

How much effort goes into your home network? Considering how many WiFi networks I see where no-one even bothered to set the ESSID to something other than ATTWiFi-992 or whatever, I'm guessing it varies a lot. One thing that seems clear though is that lots of people are frustrated with their home networks as they load on more and more devices. Even a non-tech-savvy family of 2 adults and 2 teens probably has a minimum of 10-15 WiFi devices these days given smartphones, tablets, laptops, a security camera or baby monitor, a game console, Roku/FireTV/Chromecast etc.

The fact that this technology works as well as it does is testament to how inefficiently our radio spectrum is being used. Think of the whole FM Radio, TV, and spectrum in use for business, police, fire, and soforth. Something like 50MHz to 1GHz is in my opinion utterly wasted compared to what could be done with modern techniques like Frequency Hopping Spread Spectrum or dynamic frequency allocations via negotiation protocols (compare to the way DHCP works for IP addresses).


For Dave, the QoS update

2016 November 19
by Daniel Lakeland

I've been using Fireqos for my home network. Since switching recently to Gigabit fiber it required a lot of reconfiguring of my internal network. In the process I discovered a few things:

  1. Typical consumer level routers from even a few years ago can't even begin to handle a gigabit through their firewall. You need something with an x86 type processor or a very modern ARM based consumer router. My Buffalo router could push about 150Mbps through the firewall at most.
  2. QoS is still important at gigabit speeds. You can push a lot of data into buffers very quickly. Furthermore keeping things well paced actually allows you to go faster because acks make it back to where they're going.
  3. Don't forget the effect of crappy cables. Replace your patch cables that you have lying around that came with whatever stuff you used to have with something good. I made my own patch cables with a crimp tool and high quality Cat5e, and it improved packet loss issues that may have been an issue before as well.
  4. As Dave Taht suggested, switching from pfifo to fq_codel helped for the ssh connection class. In particular, I had been thinking of this class as mainly handling keystrokes and things for ssh sessions, but of course scp and rsync both like to push data over ssh. Because of that, I needed to put an fq_codel qdisc on the ssh class so my keystrokes would make it even when some rsync was going.
  5. Too many things have changed at once for me to know whether fq_codel would have any affect on my voip RTP queue. But I suspect not. Every 0.02 seconds it'll send a single udp packet for each call. Each packet is around 1000 bytes. There are typically 1-4 calls at most. They jump to the front of the line due to the QoS and so the queue is never going to have more than 1 or 2 packets in it. The overhead of fq_codel makes no sense when the queue never gets longer than 3 packets and never takes longer than .00002 seconds to drain. If I have any issues though, I'll revisit.