Skip to content

Commit

Permalink
use fully qualified table names everywhere
Browse files Browse the repository at this point in the history
Fixes #8
  • Loading branch information
rcgoodfellow committed Nov 9, 2022
1 parent 86aed5a commit e9cc892
Show file tree
Hide file tree
Showing 12 changed files with 278 additions and 133 deletions.
57 changes: 39 additions & 18 deletions codegen/rust/src/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::{
expression::ExpressionGenerator,
rust_type,
qualified_table_function_name, rust_type,
statement::{StatementContext, StatementGenerator},
try_extract_prefix_len, Context,
};
Expand Down Expand Up @@ -34,6 +34,40 @@ impl<'a> ControlGenerator<'a> {
for control in &self.ast.controls {
self.generate_control(control);
}

let ingress = match self.ast.get_control("ingress") {
Some(i) => i,
None => return,
};
let tables = ingress.tables(self.ast);
for (cs, t) in tables {
let qtn = qualified_table_function_name(&cs, t);
let qtfn = qualified_table_function_name(&cs, t);
let control = cs.last().unwrap().1;
let (_, mut param_types) = self.control_parameters(control);
for var in &control.variables {
if let Type::UserDefined(typename) = &var.ty {
if self.ast.get_extern(typename).is_some() {
let extern_type = format_ident!("{}", typename);
param_types.push(quote! {
&p4rs::externs::#extern_type
})
}
}
}
let (type_tokens, table_tokens) =
self.generate_control_table(control, t, &param_types);
let qtn = format_ident!("{}", qtn);
let qtfn = format_ident!("{}", qtfn);
self.ctx.functions.insert(
qtn.to_string(),
quote! {
pub fn #qtfn() -> #type_tokens {
#table_tokens
}
},
);
}
}

pub(crate) fn generate_control(
Expand All @@ -51,7 +85,8 @@ impl<'a> ControlGenerator<'a> {

let tables = control.tables(self.ast);
for (cs, table) in tables {
let c = *cs.last().unwrap();
let c = cs.last().unwrap().1;
let qtn = qualified_table_function_name(&cs, table);
let (_, mut param_types) = self.control_parameters(c);
for var in &c.variables {
if let Type::UserDefined(typename) = &var.ty {
Expand All @@ -70,24 +105,10 @@ impl<'a> ControlGenerator<'a> {
std::sync::Arc<dyn Fn(#(#param_types),*)>
>
};
let name = format_ident!("{}_table_{}", c.name, table.name);
let qtn = format_ident!("{}", qtn);
params.push(quote! {
#name: &#table_type
#qtn: &#table_type
});

// for local tables, generate a constructor function
if c == control {
let (type_tokens, table_tokens) =
self.generate_control_table(control, table, &param_types);
self.ctx.functions.insert(
name.to_string(),
quote! {
pub fn #name() -> #type_tokens {
#table_tokens
}
},
);
}
}

let name = format_ident!("{}_apply", control.name);
Expand Down
35 changes: 33 additions & 2 deletions codegen/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ use proc_macro2::TokenStream;
use quote::{format_ident, quote};

use p4::ast::{
ControlParameter, DeclarationInfo, Direction, Expression, ExpressionKind,
Lvalue, NameInfo, Parser, Type, UserDefinedType, AST,
Control, ControlParameter, DeclarationInfo, Direction, Expression,
ExpressionKind, Lvalue, NameInfo, Parser, Table, Type, UserDefinedType,
AST,
};
use p4::hlir::Hlir;
use p4::util::resolve_lvalue;
Expand Down Expand Up @@ -331,3 +332,33 @@ fn is_rust_reference(lval: &Lvalue, names: &HashMap<String, NameInfo>) -> bool {
false
}
}

fn qualified_table_name(
chain: &Vec<(String, &Control)>,
table: &Table,
) -> String {
table_qname(chain, table, '.')
}

fn qualified_table_function_name(
chain: &Vec<(String, &Control)>,
table: &Table,
) -> String {
table_qname(chain, table, '_')
}

fn table_qname(
chain: &Vec<(String, &Control)>,
table: &Table,
sep: char,
) -> String {
let mut qname = String::new();
for c in chain {
if c.0.is_empty() {
continue;
}
qname += &format!("{}{}", c.0, sep);
}
qname += &table.name;
qname
}
14 changes: 14 additions & 0 deletions codegen/rust/src/p4struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,20 @@ impl<'a> StructGenerator<'a> {
}
}
})
} else {
structure.extend(quote! {
impl #name {
pub fn valid_header_size(&self) -> usize { 0 }

pub fn to_bitvec(&self) -> BitVec<u8, Msb0> {
bitvec![u8, Msb0; 0; 0]
}

pub fn dump(&self) -> String {
std::string::String::new()
}
}
})
}

self.ctx.structs.insert(s.name.clone(), structure);
Expand Down
101 changes: 59 additions & 42 deletions codegen/rust/src/pipeline.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
// Copyright 2022 Oxide Computer Company

use crate::{rust_type, type_size, Context, Settings};
use p4::ast::{Control, MatchKind, PackageInstance, Parser, Table, Type, AST};
use crate::{
qualified_table_function_name, qualified_table_name, rust_type, type_size,
Context, Settings,
};
use p4::ast::{
Control, Direction, MatchKind, PackageInstance, Parser, Table, Type, AST,
};
use p4::hlir::Hlir;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
Expand Down Expand Up @@ -143,8 +148,8 @@ impl<'a> PipelineGenerator<'a> {
let tables = control.tables(self.ast);
let mut tbl_args = Vec::new();
for (cs, t) in tables {
let c = cs.last().unwrap();
let name = format_ident!("{}_table_{}", c.name, t.name);
let qtfn = qualified_table_function_name(&cs, t);
let name = format_ident!("{}", qtfn);
tbl_args.push(quote! {
&self.#name
});
Expand Down Expand Up @@ -261,7 +266,8 @@ impl<'a> PipelineGenerator<'a> {

let tables = control.tables(self.ast);
for (cs, table) in tables {
let control = cs.last().unwrap();
let control = cs.last().unwrap().1;
let qtn = qualified_table_function_name(&cs, table);
let (_, mut param_types) = cg.control_parameters(control);

for var in &control.variables {
Expand All @@ -282,35 +288,26 @@ impl<'a> PipelineGenerator<'a> {
std::sync::Arc<dyn Fn(#(#param_types),*)>
>
};
let name = format_ident!("{}_table_{}", control.name, table.name);
let qtn = format_ident!("{}", qtn);
members.push(quote! {
pub #name: #table_type
pub #qtn: #table_type
});
let ctor = format_ident!("{}_table_{}", control.name, table.name);
initializers.push(quote! {
#name: #ctor()
#qtn: #qtn()
})
}

(members, initializers)
}

fn qualified_table_name(chain: &Vec<&Control>, table: &Table) -> String {
let mut qname = String::new();
for c in chain {
qname += &format!("{}.", c.name);
}
qname += &table.name;
qname
}

fn add_table_entry_method(&mut self, control: &Control) -> TokenStream {
let mut body = TokenStream::new();

let tables = control.tables(self.ast);
for (cs, table) in tables.iter() {
let qtn = Self::qualified_table_name(cs, table);
let call = format_ident!("add_{}_table_entry", table.name);
let qtn = qualified_table_name(cs, table);
let qtfn = qualified_table_function_name(cs, table);
let call = format_ident!("add_{}_entry", qtfn);
body.extend(quote! {
#qtn => self.#call(
action_id,
Expand Down Expand Up @@ -344,10 +341,9 @@ impl<'a> PipelineGenerator<'a> {

let tables = control.tables(self.ast);
for (cs, table) in tables.iter() {
let qtn = Self::qualified_table_name(cs, table);
//TODO probably a conflict with the same table name in multiple control
//blocks
let call = format_ident!("remove_{}_table_entry", table.name);
let qtn = qualified_table_name(cs, table);
let qftn = qualified_table_function_name(cs, table);
let call = format_ident!("remove_{}_entry", qftn);
body.extend(quote! {
#qtn => self.#call(keyset_data),
});
Expand All @@ -374,7 +370,7 @@ impl<'a> PipelineGenerator<'a> {
let mut names = Vec::new();
let tables = control.tables(self.ast);
for (cs, table) in &tables {
names.push(Self::qualified_table_name(cs, table));
names.push(qualified_table_name(cs, table));
}
quote! {
fn get_table_ids(&self) -> Vec<&str> {
Expand All @@ -388,8 +384,9 @@ impl<'a> PipelineGenerator<'a> {

let tables = control.tables(self.ast);
for (cs, table) in tables.iter() {
let qtn = Self::qualified_table_name(cs, table);
let call = format_ident!("get_{}_table_entries", table.name);
let qtn = qualified_table_name(cs, table);
let qtfn = qualified_table_function_name(cs, table);
let call = format_ident!("get_{}_entries", qtfn);
body.extend(quote! {
#qtn => Some(self.#call()),
});
Expand All @@ -415,10 +412,14 @@ impl<'a> PipelineGenerator<'a> {
let mut tokens = TokenStream::new();
let tables = control.tables(self.ast);
for (cs, table) in tables {
let control = cs.last().unwrap();
tokens.extend(self.add_table_entry_function(table, control));
tokens.extend(self.remove_table_entry_function(table, control));
tokens.extend(self.get_table_entries_function(table, control));
let control = cs.last().unwrap().1;
let qtfn = qualified_table_function_name(&cs, table);
tokens.extend(self.add_table_entry_function(table, control, &qtfn));
tokens.extend(
self.remove_table_entry_function(table, control, &qtfn),
);
tokens
.extend(self.get_table_entries_function(table, control, &qtfn));
}

tokens
Expand Down Expand Up @@ -473,6 +474,7 @@ impl<'a> PipelineGenerator<'a> {
&mut self,
table: &Table,
control: &Control,
qtfn: &str,
) -> TokenStream {
let keys = self.table_entry_keys(table);

Expand Down Expand Up @@ -557,7 +559,14 @@ impl<'a> PipelineGenerator<'a> {
let name = format_ident!("{}", p.name);
control_params.push(quote! { #name });
let ty = rust_type(&p.ty);
control_param_types.push(quote! { &mut #ty });
match p.direction {
Direction::Out | Direction::InOut => {
control_param_types.push(quote! { &mut #ty });
}
_ => {
control_param_types.push(quote! { &#ty });
}
}
}

for p in &a.parameters {
Expand All @@ -581,7 +590,7 @@ impl<'a> PipelineGenerator<'a> {
}

let aname = &action.name;
let tname = format_ident!("{}_table_{}", control.name, table.name);
let tname = format_ident!("{}", qtfn);
action_match_body.extend(quote! {
#aname => {
#(#parameter_tokens)*
Expand Down Expand Up @@ -619,7 +628,7 @@ impl<'a> PipelineGenerator<'a> {
x => panic!("unknown {} action id {}", #name, x),
});

let name = format_ident!("add_{}_table_entry", table.name);
let name = format_ident!("add_{}_entry", qtfn);
quote! {
// lifetime is due to
// https://github.com/rust-lang/rust/issues/96771#issuecomment-1119886703
Expand All @@ -644,21 +653,28 @@ impl<'a> PipelineGenerator<'a> {
&mut self,
table: &Table,
control: &Control,
qtfn: &str,
) -> TokenStream {
let keys = self.table_entry_keys(table);
let n = table.key.len();

//let tname = format_ident!("{}", table.name);
let tname = format_ident!("{}_table_{}", control.name, table.name);
let name = format_ident!("remove_{}_table_entry", table.name);
let tname = format_ident!("{}", qtfn);
let name = format_ident!("remove_{}_entry", qtfn);

let mut control_params = Vec::new();
let mut control_param_types = Vec::new();
for p in &control.parameters {
let name = format_ident!("{}", p.name);
control_params.push(quote! { #name });
let ty = rust_type(&p.ty);
control_param_types.push(quote! { &mut #ty });
match p.direction {
Direction::Out | Direction::InOut => {
control_param_types.push(quote! { &mut #ty });
}
_ => {
control_param_types.push(quote! { &#ty });
}
}
}

for var in &control.variables {
Expand Down Expand Up @@ -715,11 +731,12 @@ impl<'a> PipelineGenerator<'a> {

fn get_table_entries_function(
&mut self,
table: &Table,
control: &Control,
_table: &Table,
_control: &Control,
qtfn: &str,
) -> TokenStream {
let name = format_ident!("get_{}_table_entries", table.name);
let tname = format_ident!("{}_table_{}", control.name, table.name);
let name = format_ident!("get_{}_entries", qtfn);
let tname = format_ident!("{}", qtfn);

quote! {
pub fn #name(&self) -> Vec<p4rs::TableEntry> {
Expand Down
Loading

0 comments on commit e9cc892

Please sign in to comment.