Pyretic: A Language for Composing SDN Policies (text)
by
Sasha Shkrebets
—
last modified
Mar 20, 2023 08:07 AM
In this lecture, we'll talk about Pyretic.
Which is a high level SDN Programming Language,
that makes it easy to compose different kinds of network control.
Pyretic is an SDN Language and Runtime.
Welcome back. In this lecture, we'll talk about Pyretic.
Which is a high level SDN Programming Language,
that makes it easy to compose different kinds of network control.
Pyretic is an SDN Language and Runtime.
The Language is a way of expressing high-level policies and
the Runtime is a way of "compiling" those polices to OpenFlow rules.
Pyretic allows programmers to specify policies on something called located
packets, which is a combination of a packet and its location in the network.
In Pyretic, network policies take as input packets and
return packets at different locations in the network.
Pyretic allows operators to express Boolean predicates and
policies in contrast to OpenFlow.
Which can really only express sequences of match action rules, with exceptions.
Pyretic introduces the notion of a virtual packet header field
that can refer to various properties of the packet.
Such as it's location, various tags that may be on the packet and so forth.
Pyretic also allows an operator to compose modular
policies both in parallel and apply them either in parallel or
in sequence on a packet or sequence of packets.
Let's talk a little bit more about network policies in Pyretic and
how they differ from OpenFlow.
In OpenFlow policies are bit patterns that is matches on bits in a packet header.
In contrast, in Pyretic,
these policies are functions that map packets to other packets.
Here are some examples of network policies.
Identity simply returns to the original packet.
None is equivalent to a drop.
It returns the empty set.
Match returns the packet if the field f matches the value v,
otherwise it returns none.
Modify returns the packet with the field f set to the value v.
Forward simply modifies a virtual packet header field called output,
effectively sending the packet on a switch's output board.
And flood returns one packet for each port on the network's spanning tree.
In OpenFlow, packets either match a rule, or they don't, and
they fall through to the next rule.
So simple expressions of Boolean predicates like or, not, and
so forth are actually rather difficult to reason about.
Pyretics match function, outputs the packet, or
nothing depending on the predicate that's expressed in higher level constructs.
Here's an example of such a predicate in pyretic that returns the packet if
the destination IP address matches either 10.0.0.3 or 10.0.0.4.
Pyretic's Virtual Packet Header Fields are a unified way of representing packet
metadata.
In Pyretic a packet is nothing more than a dictionary that maps a field name, or
a virtual packet header, to a value.
These fields might include not only the real packet headers but
also virtual packet headers such as the packet's location in the network.
Including the switch where it resides,
and the input port that it arrived on at that switch.
As we've discussed, Pyretics' mod function can also modify packet metadata,
which might include either real or virtual packet header fields.
Pyretic allows for two types of policy composition.
One is sequential composition which performs one operation
followed by the next.
In this example, we have a simple firewall
which returns only packets matching a particular destination IP address
followed by a switch that forwards the packet out a particular output port.
In Pyretic of course,
that's equivalent to modifying the outport virtual packet header.
Parallel composition performs both operations simultaneously,
on multiple copies of the packet.
There are various types of operations that can be performed in parallel,
such as counting, in parallel with form.
But another common operation in Pyretic is to express parallel operations
as a disjunction.
In this example we have two policies composed in parallel.
But notice that it's not possible for both of these policies to return a packet
because the destination IP address of the packet can only take one value.
In Pyretic an operator creates a query
to see various streams of packets at the control.
The programmer then registers a call back that's invoked
anytime a new packet arrives corresponding to that query.
Dynamic policies are policies whose forwarding behavior changes.
They're represented as a time series of static policies.
And the value in Pyretic is a special variable called self.policy.
A common programming idiom that we'll see is to set a default policy for
the variable self.policy.
And register a callback function that updates
the value of this special variable.
Two particular examples where we'll see dynamic policies
are simple learning switch, which I'll show you in this lecture,
in a firewall which you'll implement in the assignment.
Here's the example set up for the Pyretic switch.
Pyrectic controller speaks to the switch and
will use a simple three node mini net to poligy to explore it's behavior.
Here's an example.
Learning switch written in Pyretic.
We can already see that it's much simpler than the equivalent program written in
create a learning switch.
We inherit from Pyretic's dynamic policy class the initial state sets to
the query value and registers a callback for that query.
That query simply says send the packet to the controller every time any
particular switch in the network sees a packet with a new source Mac address.
The default policy that we set is to flood, but
any time a new packet arrives you learn new Mac call back is invoked.
And that call MAC redefines the policy function.
To see a learning switch in action, let's start the Mininet controller and
let's invoke our simple MAC learner.
As expected,
we can see that the hosts can ping one another in the simple [INAUDIBLE].
In the assignment, you'll modify this control behavior so
that the controller acts like a firewall.
In summary Pyretic makes writing complex policies easy.
Network policies are expressed as functions that
can express predicates on packets.
They can operate on real as well as virtual packet headers.
And Pyretic makes it possible to compose multiple policies
that act on a single stream of packets.
Composition makes it easy for policies to build on one another.