-
Notifications
You must be signed in to change notification settings - Fork 51
NetKAT Python Syntax
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.)
A predicate is a boolean condition for matching packets. It's generally used in filter
and IfThenElse
policies,
outlined in the next section.
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. |
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.
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.
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. |
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.
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)
)