Skip to content

NetKAT Python Syntax

Craig Riecke edited this page Jun 14, 2016 · 1 revision

The NetKAT Python syntax requires the Frenetic Python extension to be installed (which is done by default on the Frenetic User and Developer VM's). Your Python SDN net app speaks to Frenetic through the REST/JSON interface, but all those details are transparent to you.

This syntax has the following benefits:

  • You can write dynamic programs that change the NetKAT switch policy at will.
  • It uses Python, which is widely known and used. And you can leverage all the Python constructs: variables, conditionals, loops, classes, etc.
  • It has plenty of syntactic sugar to make writing programs easier than other NetKAT dialects. For example, you can test a field against multiple values at once, and copy a packet with a single SetPort call.

And the following limitations:

  • Because the dialect is function-call-based, you have to call constructs within constructs to set the precedence. This makes programs more verbose. (On the other hand, there are very few precedence rules to remember.)

Predicates

A predicate is a boolean condition for matching packets. It's generally used in filter and IfThenElse policies, outlined in the next section.

Primitives

Each of the following primitives ending with Eq (except IP4SrcEq and IP4DstEq) have the following variants:

Variant Matches Packet with Ethernet Type...
EthTypeEq(0x800) Equal to 0x800
EthTypeEq(0x800,0x806) Equal to 0x800 OR 0x806
EthTypeEq([0x800,0x806]) Equal to 0x800 OR 0x806
EthTypeNotEq(0x800) Any except 0x800
EthTypeNotEq(0x800,0x806) Any except 0x800 OR 0x806
EthTypeNotEq([0x800,0x806]) Any except 0x800 OR 0x806
Predicate Matches Packets With...
False matches no packets
EthDstEq("01:4a:6f:22:1f:42") Ethernet destination address: a string of 6-byte colon separated hex.
EthSrcEq("01:4a:6f:22:1f:42") Ethernet source address: a string of 6-byte colon separated hex.
EthTypeEq(0x800) Ethernet type. For VLAN packets, this is the type of the inner packet, per OpenFlow 1.0
IP4DstEq("192.168.57.100") IPv4 desintation address: either host "192.168.57.100" or a network and mask ("192.168.57.0",24)`
IP4SrcEq("192.168.57.100") IPv4 source address: either host "192.168.57.100" or a network and mask ("192.168.57.0",24)`
IPProtoEq(6) IPv4 protocol number or ARP opcode. Must be decimal and fit in 16 bits.
PortEq(2) Ingress port number. Must be less than 65520
SwitchEq(1981745) Ingress switch datapath ID.
TCPSrcPortEq(12834) TCP/UDP source port
TCPDstPortEq(80) TCP/UDP destination port.
True matches all packets
VlanEq(1000) VLAN id.
VlanPcpEq(1) VLAN PCP. priority code point.

Combinations

Predicate Matches Packets With...
( pred ) the given predicate matching. The parentheses technically do not nothing, but override precedence rules
not pred the given predicate not matching
Not(pred) equivalent to not pred
pred1 & pred2 both pred1 and pred2 matching
And([pred1, pred2, ...]) equivalent to pred1 & pred2 & ...
`pred1 pred2`
`Or([pred1, pred2, ...]) equivalent to `pred1

not has highest precedence, meaning it binds the most tightly and is executed first, followed by & then |. This is the precedence order found in most programming languages as well. The functional versions of the predicates must be composed like regular functions, and so the innermost predicates are evaluated first and precedence rules are not needed. You can mix operators and function forms, but it's a best practice to use one or the other.

Policies

A NetKAT policy directs the switch to perform an action on a packet. Unlike predicates, the only Python policy that accepts is a list is SetPort - this effectively copies a packet and sends the copies out multiple ports.

Primitives

Policy Does This With a Packet...
Drop() Drops the packet
Filter(pred) Accepts all packets that meet the predicate. Drops any other packets
Id() Accepts all packets
SetEthDst("01:4a:6f:22:1f:42") Sets the ethernet destination address: a string of 6-byte colon separated hex.
SetEthSrc("01:4a:6f:22:1f:42") Sets the ethernet source address: a string of 6-byte colon separated hex.
SetEthType(0x800) Sets the ethernet type. For VLAN packets, sets inner packet type
SetIP4Dst("192.168.57.100") Sets the IPv4 desintation address. Must be an address string.
SetIP4Src("192.168.57.100) Sets the IPv4 source address. Must be an address string.
SetIPProto(6) Sets the IPv4 protocol number or ARP opcode. Must be decimal and fit in 16 bits.
SetPort(3,4,5) Send packet to a particular egress port or ports, can be a single integer or list
SendToController("tag") Sends packet to the OpenFlow controller.
SetQuery("tag") Counts packet in a statistics bucket named tag.
SetTCPSrcPort(12834) Sets the TCP/UDP source port
SetTCPDstPort(80) Sets the TCP/UDP destination port.
SetVlan(1000) Sets the VLAN id. Implicitly wraps the packet in a VLAN header
SetVlanPcp(1) Sets the VLAN PCP, priority code point. Implicitly wraps the packet in a VLAN header.

Combinations

Policy Does This With a Packet...
( pol ) Executes pol. Technically the parentheses do nothing but overrides precedence rules.
pol1 >> pol2 Executes pol1, then (possibly) pol2 in sequence.
Seq([pol1, pol2, ...]) Equivalent to pol1 >> pol2 >> pol3 >> ...
`pol1 pol2`
Union([pol1, pol2, ...]) Equivalent to `pol1
IfThenElse(pred,truepol,falsepol) Evaluates the predicate and, if true, executes truepol. Otherwise it executes falsepol

>> has the highest precedence, meaning it binds tighter than other operators and is executed first. | has next highest. All function-style combinations are evaluated in the natural order.

Example

Filter(SwitchEq(1)) >>
  IfThenElse( EthSrcEq("00:00:00:00:00:01"), SetPort(1),
    IfThenElse( EthSrcEq("00:00:00:00:00:02"), SetPort(2),
      IfThenElse( EthSrcEq("00:00:00:00:00:03"), SetPort(3),
        SetPort(4)
      )
    )
  )
|
Filter(SwitchEq(2)) >> (
  Filter(EthTypeEq(0x800) & IP4SrcEq("192.168.0.1")) >> SetPort(1)
  | Filter(EthTypeEq(0x800) & IP4SrcEq("192.168.0.2")) >> SetPort(2)
  | Filter(EthTypeEq(0x800) & IP4SrcEq("192.168.0.3")) >> SetPort(3)
)