Skip to content

Commit

Permalink
Merge pull request #127 from frenetic-lang/ip-mask
Browse files Browse the repository at this point in the history
Add support for IP masks
  • Loading branch information
seliopou committed Jun 23, 2014
2 parents e43fa87 + 39faf5c commit 1c83d3a
Show file tree
Hide file tree
Showing 11 changed files with 251 additions and 129 deletions.
4 changes: 4 additions & 0 deletions lib/OpenFlow0x04_Core.ml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ type int12 = int16
let val_to_mask v =
{ m_value = v; m_mask = None }

let ip_to_mask (p,m) =
if m = 32l then { m_value = p; m_mask = None }
else { m_value = p; m_mask = Some m }

type switchId = int64

type groupId = int32
Expand Down
2 changes: 2 additions & 0 deletions lib/OpenFlow0x04_Core.mli
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ type int12 = int16

val val_to_mask : 'a1 -> 'a1 mask

val ip_to_mask : (nwAddr * int32) -> nwAddr mask

type switchId = int64

type groupId = int32
Expand Down
6 changes: 4 additions & 2 deletions lib/SDN_OpenFlow0x01.ml
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@ let from_pattern (pat : AL.Pattern.t) : Core.pattern =
; Core.dlVlanPcp = pat.AL.Pattern.dlVlanPcp
; Core.nwSrc = (match pat.AL.Pattern.nwSrc with
| None -> None
| Some v -> Some { Core.m_value = v; Core.m_mask = None })
| Some (p,m) -> let mo = if m = 32l then None else Some m in
Some { Core.m_value = p; Core.m_mask = mo })
; Core.nwDst = (match pat.AL.Pattern.nwDst with
| None -> None
| Some v -> Some { Core.m_value = v; Core.m_mask = None })
| Some (p,m) -> let mo = if m = 32l then None else Some m in
Some { Core.m_value = p; Core.m_mask = mo })
; Core.nwProto = pat.AL.Pattern.nwProto
; Core.nwTos = None
; Core.tpSrc = pat.AL.Pattern.tpSrc
Expand Down
4 changes: 2 additions & 2 deletions lib/SDN_OpenFlow0x04.ml
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ let from_pattern (pat : AL.Pattern.t) : Core.oxmMatch * Core.portId option =
Core.OxmVlanVId (v_to_m x))
pat.AL.Pattern.dlVlan
; Misc.map_option (fun x -> Core.OxmVlanPcp x) pat.AL.Pattern.dlVlanPcp
; Misc.map_option (fun x -> Core.OxmIP4Src (v_to_m x)) pat.AL.Pattern.nwSrc
; Misc.map_option (fun x -> Core.OxmIP4Dst (v_to_m x)) pat.AL.Pattern.nwDst
; Misc.map_option (fun x -> Core.(OxmIP4Src (ip_to_mask x))) pat.AL.Pattern.nwSrc
; Misc.map_option (fun x -> Core.(OxmIP4Dst (ip_to_mask x))) pat.AL.Pattern.nwDst
; Misc.map_option (fun x -> Core.OxmIPProto x) pat.AL.Pattern.nwProto
; Misc.map_option (fun x -> Core.OxmTCPSrc (v_to_m x)) pat.AL.Pattern.tpSrc
; Misc.map_option (fun x -> Core.OxmTCPDst (v_to_m x)) pat.AL.Pattern.tpDst
Expand Down
178 changes: 120 additions & 58 deletions lib/SDN_Types.ml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ let format_int (fmt : Format.formatter) (v:int) =
let format_int32 (fmt : Format.formatter) (v:int32) =
Format.fprintf fmt "%lu" v

let format_ip_mask (fmt : Format.formatter) ((p,m) : nwAddr * int32) =
Format.fprintf fmt "%a%s"
format_ip p
(if m = 32l then "" else Printf.sprintf "/%ld" m)

let make_string_of formatter x =
let open Format in
let buf = Buffer.create 100 in
Expand All @@ -37,14 +42,74 @@ let make_string_of formatter x =

module Pattern = struct

module Ip = struct
type t = nwAddr * int32

let match_all = (0l, 0l)

let unsafe_shift (p, m) =
match Int32.(to_int (sub 32l m)) with
| 32 -> 0l
| i -> Int32.shift_right_logical p i

let check_mask m =
if m < 0l || m > 32l then
failwith "Pattern.Ip: invalid mask"

let shift (p, m) =
check_mask m;
unsafe_shift (p, m)

let less_eq (p1, m1) (p2, m2) =
m1 >= m2 && begin
check_mask m2;
unsafe_shift (p1, m2) = unsafe_shift (p2, m2)
end

let eq (p1, m1) (p2, m2) =
m1 = m2 && (m1 = 0l || begin
check_mask m1;
unsafe_shift (p1, m1) = unsafe_shift (p2, m2)
end)

let join (p1, m1) (p2, m2) =
let rec loop m =
if m = 0l then
(0l, 0l)
else if unsafe_shift (p1, m) = unsafe_shift (p2, m) then
(p1, m)
else
loop Int32.(sub m 1l)
in
let m = min m1 m2 in
check_mask m;
loop m

let intersect ip1 ip2 =
if less_eq ip1 ip2 then
Some ip1
else if less_eq ip2 ip1 then
Some ip2
else
None

let compatible ip1 ip2 =
match intersect ip1 ip2 with
| Some _ -> true
| None -> false

let format = format_ip_mask
let string_of ip = make_string_of format ip
end

type t =
{ dlSrc : dlAddr option
; dlDst : dlAddr option
; dlTyp : dlTyp option
; dlVlan : dlVlan
; dlVlanPcp : dlVlanPcp option
; nwSrc : nwAddr option
; nwDst : nwAddr option
; nwSrc : Ip.t option
; nwDst : Ip.t option
; nwProto : nwProto option
; tpSrc : tpPort option
; tpDst : tpPort option
Expand All @@ -63,70 +128,67 @@ module Pattern = struct
; tpDst = None
; inPort = None }

(* TODO(jnf): rename subseteq ?*)
let less_eq p1 p2 =
let check m1 m2 =
let check f m1 m2 =
match m2 with
| None -> true
| Some(v2) ->
begin match m1 with
| None -> false
| Some(v1) -> v1 = v2
end
in
check p1.dlSrc p2.dlSrc
&& check p1.dlDst p2.dlDst
&& check p1.dlTyp p2.dlTyp
&& check p1.dlVlan p2.dlVlan
&& check p1.dlVlanPcp p2.dlVlanPcp
&& check p1.nwSrc p2.nwSrc
&& check p1.nwDst p2.nwDst
&& check p1.nwProto p2.nwProto
&& check p1.tpSrc p2.tpSrc
&& check p1.tpDst p2.tpDst
&& check p1.inPort p2.inPort
| Some(v1) -> f v1 v2
end in
check (=) p1.dlSrc p2.dlSrc
&& check (=) p1.dlDst p2.dlDst
&& check (=) p1.dlTyp p2.dlTyp
&& check (=) p1.dlVlan p2.dlVlan
&& check (=) p1.dlVlanPcp p2.dlVlanPcp
&& check Ip.less_eq p1.nwSrc p2.nwSrc
&& check Ip.less_eq p1.nwDst p2.nwDst
&& check (=) p1.nwProto p2.nwProto
&& check (=) p1.tpSrc p2.tpSrc
&& check (=) p1.tpDst p2.tpDst
&& check (=) p1.inPort p2.inPort

let eq p1 p2 =
p1 = p2

let disjoint p1 p2 =
let check m1 m2 =
let check f m1 m2 =
match m1, m2 with
| None, _ -> false
| _ , None -> false
| Some(v1), Some(v2) -> not (v1 = v2)
in
check p1.dlSrc p2.dlSrc
|| check p1.dlDst p2.dlDst
|| check p1.dlTyp p2.dlTyp
|| check p1.dlVlan p2.dlVlan
|| check p1.dlVlanPcp p2.dlVlanPcp
|| check p1.nwSrc p2.nwSrc
|| check p1.nwDst p2.nwDst
|| check p1.nwProto p2.nwProto
|| check p1.tpSrc p2.tpSrc
|| check p1.tpDst p2.tpDst
|| check p1.inPort p2.inPort

let meet p1 p2 =
let meeter m1 m2 =
| None , None -> true
| Some v1, Some v2 -> f v1 v2
| _ , _ -> false in
check (=) p1.dlSrc p2.dlSrc
&& check (=) p1.dlDst p2.dlDst
&& check (=) p1.dlTyp p2.dlTyp
&& check (=) p1.dlVlan p2.dlVlan
&& check (=) p1.dlVlanPcp p2.dlVlanPcp
&& check Ip.eq p1.nwSrc p2.nwSrc
&& check Ip.eq p1.nwDst p2.nwDst
&& check (=) p1.nwProto p2.nwProto
&& check (=) p1.tpSrc p2.tpSrc
&& check (=) p1.tpDst p2.tpDst
&& check (=) p1.inPort p2.inPort

let eq_join x1 x2 =
if x1 = x2 then Some x1 else None

let join p1 p2 =
let joiner m m1 m2 =
match m1, m2 with
| Some(v1), Some(v2) when v1 = v2 ->
Some(v1)
| _ , _ ->
None
in
{ dlSrc = meeter p1.dlSrc p2.dlSrc
; dlDst = meeter p1.dlDst p2.dlDst
; dlTyp = meeter p1.dlTyp p2.dlTyp
; dlVlan = meeter p1.dlVlan p2.dlVlan
; dlVlanPcp = meeter p1.dlVlanPcp p2.dlVlanPcp
; nwSrc = meeter p1.nwSrc p2.nwSrc
; nwDst = meeter p1.nwDst p2.nwDst
; nwProto = meeter p1.nwProto p2.nwProto
; tpSrc = meeter p1.tpSrc p2.tpSrc
; tpDst = meeter p1.tpDst p2.tpDst
; inPort = meeter p1.inPort p2.inPort
}
| Some v1, Some v2 ->
m v1 v2
| _ ->
None in
{ dlSrc = joiner eq_join p1.dlSrc p2.dlSrc
; dlDst = joiner eq_join p1.dlDst p2.dlDst
; dlTyp = joiner eq_join p1.dlTyp p2.dlTyp
; dlVlan = joiner eq_join p1.dlVlan p2.dlVlan
; dlVlanPcp = joiner eq_join p1.dlVlanPcp p2.dlVlanPcp
; nwSrc = joiner (fun x y -> Some(Ip.join x y)) p1.nwSrc p2.nwSrc
; nwDst = joiner (fun x y -> Some(Ip.join x y)) p1.nwDst p2.nwDst
; nwProto = joiner eq_join p1.nwProto p2.nwProto
; tpSrc = joiner eq_join p1.tpSrc p2.tpSrc
; tpDst = joiner eq_join p1.tpDst p2.tpDst
; inPort = joiner eq_join p1.inPort p2.inPort }

let format (fmt:Format.formatter) (p:t) : unit =
let first = ref true in
Expand All @@ -144,8 +206,8 @@ module Pattern = struct
format_field "vlanId" format_int p.dlVlan;
format_field "vlanPcp" format_int p.dlVlanPcp;
format_field "nwProto" format_hex p.nwProto;
format_field "ipSrc" format_ip p.nwSrc;
format_field "ipDst" format_ip p.nwDst;
format_field "ipSrc" format_ip_mask p.nwSrc;
format_field "ipDst" format_ip_mask p.nwDst;
format_field "tcpSrcPort" format_int p.tpSrc;
format_field "tcpDstPort" format_int p.tpDst;
format_field "port" format_int32 p.inPort;
Expand Down
65 changes: 47 additions & 18 deletions lib/SDN_Types.mli
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
tables to realize actions efficiently. This requires a global analysis
of all the actions in a flow table. Therefore, Frenetic needs to
supply the entire flow table at once and cannot add and remove flow table
entries individually. *)
entries individually *)

(** {1 OpenFlow Identifier Types}
Expand All @@ -42,37 +42,65 @@ exception Unsupported of string
(** {1 Packet Forwarding} *)

module Pattern : sig
(** WARNING: There are dependencies between different fields that must be met. *)

module Ip : sig
type t = nwAddr * int32

(** [match_all] is pattern that matches any address *)
val match_all : t

(** [less_eq x1 x2] returns true when [x2] matches any address that [x1] will
match *)
val less_eq : t -> t -> bool

(** [eq p1 p2] returns true when [p1] and [p2] match the same set of
addresses *)
val eq : t -> t -> bool

(** [join p1 p2] is the least pattern [pm] such that [less_eq p1 pm] and
[less_eq p2 pm] *)
val join : t -> t -> t

(** [intersect x1 x2] returns the intersection of when [x1] and [x2] *)
val intersect : t -> t -> t option

(** [compatible x1 x2] returns true when [x1] and [x2] have a non-empty intersection *)
val compatible : t -> t -> bool

(** [ip_shift x] returns an [int32] after shifting [x] by its mask *)
val shift : t -> int32

val format : Format.formatter -> t -> unit
val string_of : t -> string
end

(** WARNING: There are dependencies between different fields that must be met *)
type t =
{ dlSrc : dlAddr option
; dlDst : dlAddr option
; dlTyp : dlTyp option
; dlVlan : dlVlan
; dlVlanPcp : dlVlanPcp option
; nwSrc : nwAddr option
; nwDst : nwAddr option
; nwSrc : Ip.t option
; nwDst : Ip.t option
; nwProto : nwProto option
; tpSrc : tpPort option
; tpDst : tpPort option
; inPort : portId option }

(** [match_all] is pattern that matches any packet. *)
(** [match_all] is pattern that matches any packet *)
val match_all : t

(** [less_eq p1 p2] returns true when [p2] matches any packet that [p1] will
match. *)
match *)
val less_eq : t -> t -> bool

(** [eq p1 p2] returns true when [p1] and [p2] match the same set of packets *)
val eq : t -> t -> bool

(** [disjoint p1 p2] returns true when there are no packets that [p1] and [p2]
can simultaneously match. *)
val disjoint : t -> t -> bool

(** [meet p1 p2] is the least pattern [pm] such that [less_eq p1 pm] and
(** [join p1 p2] is the least pattern [pm] such that [less_eq p1 pm] and
[less_eq p2 pm] *)
val meet : t -> t -> t
val join : t -> t -> t

val format : Format.formatter -> t -> unit
val string_of : t -> string
Expand Down Expand Up @@ -112,8 +140,8 @@ type par = seq list
type group = par list

type timeout =
| Permanent (** No timeout. *)
| ExpiresAfter of int16 (** Time out after [n] seconds. *)
| Permanent (** No timeout *)
| ExpiresAfter of int16 (** Time out after [n] seconds *)

type flow = {
pattern: Pattern.t;
Expand All @@ -128,10 +156,10 @@ type flowTable = flow list

(** {1 Controller Packet Processing} *)

(** The payload for [packetIn] and [packetOut] messages. *)
(** The payload for [packetIn] and [packetOut] messages *)
type payload =
| Buffered of bufferId * bytes
(** [Buffered (id, buf)] is a packet buffered on a switch. *)
(** [Buffered (id, buf)] is a packet buffered on a switch *)
| NotBuffered of bytes


Expand All @@ -158,9 +186,9 @@ type switchFeatures = {

(* {1 Statistics} *)

(** The body of a reply to an individual flow statistics request. *)
(** The body of a reply to an individual flow statistics request *)
type flowStats = {
flow_table_id : int8; (** ID of table flow came from. *)
flow_table_id : int8; (** ID of table flow came from *)
flow_pattern : Pattern.t;
flow_duration_sec: int32;
flow_duration_nsec: int32;
Expand All @@ -187,5 +215,6 @@ val format_flowTable : Format.formatter -> flowTable -> unit

val string_of_action : action -> string
val string_of_seq : seq -> string
val string_of_par : par -> string
val string_of_flow : flow -> string
val string_of_flowTable : flowTable -> string
Loading

0 comments on commit 1c83d3a

Please sign in to comment.