<Middlebox name="lb7">
  <Description>
  Layer-7 load balancer based on HAProxy vmware appliance.
  </Description>
  <Zones>
    <Zone name="inet" description="Internet" />
    <Zone name="srvr" description="Web server farm" />
  </Zones>
  <TransformationFns>
    <TransformationFn name="Dnat_fwd">
      <Param description="selected webserver">w</Param>
      <Param description="new source port">sp</Param>
      <Rewrite field="dstmac" value="Mac(w)" />
      <Rewrite field="dstip" value="Ip(w)" />
      <Rewrite field="srcmac" value="Mac(LB)" />
      <Rewrite field="srcip" value="Ip(LB)" />
      <Rewrite field="srcport" value="sp" />
    </TransformationFn>
  </TransformationFns>

  <ProcessingRules>
    <Rule id="1">
      <Description>New flow from client -> LB</Description>
      <LHS>
        <Z>inet</Z>
        <I>h.dstmac == Mac(LB) AND h.dstip == Ip(LB) AND h.dstport == 80</I>
        <C>NewFlow?</C>
      </LHS>
      <RHS>
        <Assign>tcp_cl = Tcp.new</Assign>
        <Assign>d_cl = Data.new</Assign>
        <Assign>h_cl = h</Assign>
        <SetState zone="inet" key="h.5tpl" value="{tcp_cl; d_cl; h_cl}" />
      </RHS>
    </Rule>
    <Rule id="2">
      <Description>Client to LB traffic. Buffer data in d_cl</Description>
      <LHS>
        <Z>inet</Z>
        <I>h.dstmac == Mac(LB) AND h.dstip == Ip(LB) AND h.dstport == 80</I>
        <C>! NewFlow?</C>
        <GetState zone="inet" key="h.5tpl" assignto="s" />
      </LHS>
      <RHS>
        s.tcp_cl.Recv(h) AND s.d_cl.Append(d)
      </RHS>
    </Rule>
    <Rule id="3">
      <Description>LB to client traffic, with data from d_ls if available</Description>
      <LHS>
        <C>s.tcp_cl.Ready?</C>
      </LHS>
      <RHS>
        <Emit zone="inet">
          <Hdr>s.tcp_cl.Send(Rev(s.h_cl))</Hdr>
          <Payload>s.tcp_cl.Send(s.d_ls.Read)</Payload>
        </Emit>
      </RHS>
    </Rule>
    <Rule id="4">
      <Description>Entire URL/cookie becomes available in d_cl. Hence create LS TCP connection and d_ls.  Set state: hls^rev to s.</Description>
      <LHS>
        s.d_cl.UrlReady?
      </LHS>
      <RHS>
        <Assign>w = SrvrSelect</Assign>
        <Assign>s.tcp_ls = Tcp.new</Assign>
        <Assign>s.d_ls = Data.new</Assign>
        <Assign>s.h_ls = Dnat_fwd(s.h_cl, w, s.tcp_ls.srcport)</Assign>
        <SetState zone="srvr" key="Rev(s.h_ls).5tpl" value="s" />
      </RHS>
    </Rule>
    <Rule id="5">
      <Description>Server to LB traffic.  Update tcp_ls and d_ls</Description>
      <LHS>
        <Z>srvr</Z>
        <I>h.srcmac == Mac(W) AND h.srcip == Ip(W) AND h.srcport == 80</I>
        <GetState zone="srvr" key="h.5tpl" assignto="s" />
      </LHS>
      <RHS>
        s.tcp_ls.Recv(h) AND s.d_ls.Append(d)      
      </RHS>
    </Rule>
    <Rule id="6">
      <Description>LB to server traffic when tcpls becomes ready.  Reads traffic from d_ls if available.</Description>
      <LHS>
        s.tcp_ls.Ready?
      </LHS>
      <RHS>
        <Emit zone="srvr">
          <Hdr>s.tcp_ls.Send(s.ls)</Hdr>
          <Payload>s.tcp_ls.Send(s.d_cl.Read)</Payload>
        </Emit>
      </RHS>
    </Rule>
  </ProcessingRules>
</Middlebox>

