+ reorg +add simple nat64 w/o protocol specific translations
This commit is contained in:
parent
4972f550d8
commit
a408d7a803
3 changed files with 130 additions and 87 deletions
103
doc/plan.org
103
doc/plan.org
|
@ -1161,69 +1161,78 @@ check whether tables are applied correctly (type conversion
|
||||||
problems) - start tcpdump - start test program - stop tcpdump - add
|
problems) - start tcpdump - start test program - stop tcpdump - add
|
||||||
pcap to git repo - git add-commit-push - git pull - start wireshark -
|
pcap to git repo - git add-commit-push - git pull - start wireshark -
|
||||||
debug packets - analyse code - goto 1
|
debug packets - analyse code - goto 1
|
||||||
|
**** Static NAT64
|
||||||
|
Asymmetric maps: v6->v4 can match whole IPv4 Internet (/96)
|
||||||
|
But v4->v6 can only map sub range!
|
||||||
|
Using /24s (for convience) in IPv4
|
||||||
|
|
||||||
*** Performance comparison
|
*** Performance comparison
|
||||||
*** Feature/Functionality difference / overview / Challenges / limitations in P4
|
*** Feature/Functionality difference / overview / CHALLENGES / LIMITATIONS in P4
|
||||||
**** P4: cannot read key from table
|
**** P4: cannot read key from table
|
||||||
|
***** log
|
||||||
Key and mask for matching destination is in table. We need this
|
Key and mask for matching destination is in table. We need this
|
||||||
information in the action. However this information is not exposed, so
|
information in the action. However this information is not exposed, so
|
||||||
we need to specify another parameter with the same information as in
|
we need to specify another parameter with the same information as in
|
||||||
the key(s).
|
the key(s).
|
||||||
|
|
||||||
Log from slack: (2019-03-14)
|
Log from slack: (2019-03-14)
|
||||||
|
|
||||||
nico [1:55 PM]
|
nico [1:55 PM]
|
||||||
If I use LPM for matching, can I easily get the network address from P4 or do I have to use a bitmask myself? In the latter case it is not exactly clear how to get the mask from the table
|
If I use LPM for matching, can I easily get the network address from P4 or do I have to use a bitmask myself? In the latter case it is not exactly clear how to get the mask from the table
|
||||||
|
|
||||||
Nate Foster [1:58 PM]
|
Nate Foster [1:58 PM]
|
||||||
You want to retrieve the address in the packet? In a table?
|
You want to retrieve the address in the packet? In a table?
|
||||||
And do you want to do the retrieving from the data plane or the control plane? (edited)
|
And do you want to do the retrieving from the data plane or the control plane? (edited)
|
||||||
|
|
||||||
nico [2:00 PM]
|
nico [2:00 PM]
|
||||||
If I have a match in a table that matches on LPM, it can be any IP address in a network
|
If I have a match in a table that matches on LPM, it can be any IP address in a network
|
||||||
For calculating the NAT64/NAT46 translation, I will need the base address, i.e. network address to do subtractions/additions
|
For calculating the NAT64/NAT46 translation, I will need the base address, i.e. network address to do subtractions/additions
|
||||||
So it is fully data plane, what I would like to do
|
So it is fully data plane, what I would like to do
|
||||||
I'll commit sample code to show the use case more clearly
|
I'll commit sample code to show the use case more clearly
|
||||||
https://gitlab.ethz.ch/nicosc/master-thesis/blob/master/p4src/static-mapping.p4#L73
|
https://gitlab.ethz.ch/nicosc/master-thesis/blob/master/p4src/static-mapping.p4#L73
|
||||||
GitLab
|
GitLab
|
||||||
p4src/static-mapping.p4 · master · nicosc / master-thesis
|
p4src/static-mapping.p4 · master · nicosc / master-thesis
|
||||||
gitlab.ethz.ch
|
gitlab.ethz.ch
|
||||||
So the action nat64_static() is used in the table v6_networks.
|
So the action nat64_static() is used in the table v6_networks.
|
||||||
In v6_networks I use a match on `hdr.ipv6.dst_addr: lpm;`
|
In v6_networks I use a match on `hdr.ipv6.dst_addr: lpm;`
|
||||||
What I would like to be able is to get the network address ; I can do that manually, if I have the mask
|
What I would like to be able is to get the network address ; I can do that manually, if I have the mask
|
||||||
I can also re-inject this parameter by another action argument, but I'd assume that I can somewhere read this out from the table / match
|
I can also re-inject this parameter by another action argument, but I'd assume that I can somewhere read this out from the table / match
|
||||||
|
|
||||||
Nate Foster [2:15 PM]
|
Nate Foster [2:15 PM]
|
||||||
To make sure I understand, in the data plane, you want to retrieve the address in the lpm pattern? (edited)
|
To make sure I understand, in the data plane, you want to retrieve the address in the lpm pattern? (edited)
|
||||||
|
|
||||||
nico [2:16 PM]
|
nico [2:16 PM]
|
||||||
I want to retrieve the key
|
I want to retrieve the key
|
||||||
|
|
||||||
Nate Foster [2:16 PM]
|
Nate Foster [2:16 PM]
|
||||||
Wait. The value `hdr.ipv6.dst_addr` is the thing used in the match.
|
Wait. The value `hdr.ipv6.dst_addr` is the thing used in the match.
|
||||||
So you have that.
|
So you have that.
|
||||||
What you don’t have is the IPv6 address and mask put into the table by the control plane.
|
What you don’t have is the IPv6 address and mask put into the table by the control plane.
|
||||||
I assume you want the latter, right?
|
I assume you want the latter, right?
|
||||||
|
|
||||||
nico [2:17 PM]
|
nico [2:17 PM]
|
||||||
For example, if my matching key is 2001:db8::/32 and the real address is 2001:db8::f00, then I would like to retrieve 2001:db8:: and 32 from the table
|
For example, if my matching key is 2001:db8::/32 and the real address is 2001:db8::f00, then I would like to retrieve 2001:db8:: and 32 from the table
|
||||||
exactly :slightly_smiling_face:
|
exactly :slightly_smiling_face:
|
||||||
I can "fix" this by adding another argument, but it feels somewhat wrong to do that
|
I can "fix" this by adding another argument, but it feels somewhat wrong to do that
|
||||||
Because the table already knows this information
|
Because the table already knows this information
|
||||||
|
|
||||||
Nate Foster [2:26 PM]
|
Nate Foster [2:26 PM]
|
||||||
I can’t think of a way other than the action parameter hack.
|
I can’t think of a way other than the action parameter hack.
|
||||||
|
|
||||||
nico [2:26 PM]
|
nico [2:26 PM]
|
||||||
Oh, ok
|
Oh, ok
|
||||||
Is it because the information is "lost in hardware"?
|
Is it because the information is "lost in hardware"?
|
||||||
|
|
||||||
Nate Foster [2:31 PM]
|
Nate Foster [2:31 PM]
|
||||||
No you’re right that most implementations have the value in memory. And one can imagine a different table API that allowed one to retrieve it in the data plane.
|
No you’re right that most implementations have the value in memory. And one can imagine a different table API that allowed one to retrieve it in the data plane.
|
||||||
But unless I am missing something obvious, P4 hides it…
|
But unless I am missing something obvious, P4 hides it…
|
||||||
|
|
||||||
**** ICMP6: checksum over payload
|
***** Result
|
||||||
|
Need to duplicate information
|
||||||
|
|
||||||
|
**** DONE ICMP6: checksum over payload
|
||||||
- variable length, up to 65k
|
- variable length, up to 65k
|
||||||
Exists:
|
Exists!
|
||||||
**** Synchronisation with the controller
|
**** Synchronisation with the controller
|
||||||
- Double data type definition -> might differ
|
- Double data type definition -> might differ
|
||||||
- TYPE_CPU for ethernet
|
- TYPE_CPU for ethernet
|
||||||
|
|
|
@ -115,16 +115,17 @@ class L2Controller(object):
|
||||||
for mode in self.modes:
|
for mode in self.modes:
|
||||||
self.nat64_map[mode] = []
|
self.nat64_map[mode] = []
|
||||||
|
|
||||||
# specific settings -- only need the address (=offset), no mask
|
# specific settings - mapping 256 IPv6 IPs max statically (based on /24)
|
||||||
for mode in ["range_router"]:
|
for mode in ["range_router"]:
|
||||||
for net in self.v6_routes[mode]:
|
for v6_net in self.v6_routes[mode]:
|
||||||
v6_net = net['net']
|
for v4_net in self.v4_routes[mode]:
|
||||||
v4_net = self.info['v4_nat64_map'].next()
|
v4_dst = self.info['v4_nat64_map'].next()
|
||||||
|
|
||||||
self.nat64_map[mode].append({
|
self.nat64_map[mode].append({
|
||||||
"v6_network": v6_net,
|
"v6_src": v6_net['net'],
|
||||||
"v4_network": v4_net,
|
"v6_dst": self.info['nat64_prefix'] # static
|
||||||
"nat64_prefix": self.info['nat64_prefix']
|
"v4_src": v4_net['net'],
|
||||||
|
"v4_dst": v4_dst
|
||||||
})
|
})
|
||||||
|
|
||||||
self.init_boilerplate(sw_name)
|
self.init_boilerplate(sw_name)
|
||||||
|
@ -201,6 +202,10 @@ class L2Controller(object):
|
||||||
for v6route in self.v6_routes[self.mode]:
|
for v6route in self.v6_routes[self.mode]:
|
||||||
self.controller.table_add("v6_networks", "set_egress_port", [str(v6route['net'])], [str(v6route['port'])])
|
self.controller.table_add("v6_networks", "set_egress_port", [str(v6route['net'])], [str(v6route['port'])])
|
||||||
|
|
||||||
|
self.controller.table_clear("v4_networks")
|
||||||
|
for v4route in self.v4_routes[self.mode]:
|
||||||
|
self.controller.table_add("v4_networks", "set_egress_port", [str(v4route['net'])], [str(v4route['port'])])
|
||||||
|
|
||||||
if self.args.multicast_to_controller:
|
if self.args.multicast_to_controller:
|
||||||
self.listen_to_icmp6_multicast()
|
self.listen_to_icmp6_multicast()
|
||||||
|
|
||||||
|
@ -209,10 +214,10 @@ class L2Controller(object):
|
||||||
self.init_ndp_in_switch(v6addr)
|
self.init_ndp_in_switch(v6addr)
|
||||||
self.init_icmp6_echo_in_switch(v6addr)
|
self.init_icmp6_echo_in_switch(v6addr)
|
||||||
|
|
||||||
|
self.controller.table_clear("nat64")
|
||||||
self.controller.table_clear("v4_networks")
|
self.controller.table_clear("nat46")
|
||||||
for v4route in self.v4_routes[self.mode]:
|
for nat64map in self.nat64_map[self.mode]:
|
||||||
self.controller.table_add("v4_networks", "set_egress_port", [str(v4route['net'])], [str(v4route['port'])])
|
self.static_nat64_mapping(**nat64map)
|
||||||
|
|
||||||
|
|
||||||
# Disable icmp handling in the controller
|
# Disable icmp handling in the controller
|
||||||
|
@ -230,23 +235,25 @@ class L2Controller(object):
|
||||||
# # Experimental: controller does NDP, switch does ICMP6 echo reply
|
# # Experimental: controller does NDP, switch does ICMP6 echo reply
|
||||||
# self.controller.table_add("v6_addresses", "controller_reply", [str(another_addr_ns)], [str(self.task['ICMP6_NS'])])
|
# self.controller.table_add("v6_addresses", "controller_reply", [str(another_addr_ns)], [str(self.task['ICMP6_NS'])])
|
||||||
|
|
||||||
|
def static_nat64_mapping(self, v6_src, v6_dst, v4_src, v4_dst):
|
||||||
|
log.info("NAT64 map: ({} -> {} => {}), ({} -> {} -> {} (only /24)))".format(
|
||||||
|
v6_src, v6_dst, v4_dst,
|
||||||
|
v4_src, v4_dst, v6_src)
|
||||||
|
|
||||||
for nat64map in self.nat64_map[self.mode]:
|
self.controller.table_add("nat64", "nat64_static",
|
||||||
self.static_nat64_mapping(**nat64map)
|
[str(v6_src)
|
||||||
|
str(v6_dst)],
|
||||||
def static_nat64_mapping(self, nat64_prefix, v6_network, v4_network):
|
[str(v6_src.network_address),
|
||||||
log.info("NAT64 map: {} -> {} -> {}".format(nat64_prefix, v6_network, v4_network))
|
str(v4_dst.network_address),
|
||||||
|
str(v6_dst.network_address)]
|
||||||
self.controller.table_add("v6_networks", "nat64_static", [str(nat64_prefix)],
|
|
||||||
[str(v6_network.network_address),
|
|
||||||
str(v4_network.network_address),
|
|
||||||
str(nat64_prefix.network_address)]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.controller.table_add("v4_networks", "nat46_static", [str(v4_network)],
|
self.controller.table_add("nat46", "nat46_static",
|
||||||
[str(v6_network.network_address),
|
[str(v4_src)
|
||||||
str(v4_network.network_address),
|
str(v4_dst)],
|
||||||
str(nat64_prefix.network_address)]
|
[str(v6_src.network_address),
|
||||||
|
str(v4_dst.network_address),
|
||||||
|
str(v6_dst.network_address)]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ control MyIngress(inout headers hdr,
|
||||||
hdr.ipv4.diff_serv = (bit<6>)0; // no ToS
|
hdr.ipv4.diff_serv = (bit<6>)0; // no ToS
|
||||||
hdr.ipv4.ecn = (bit<2>)0; // unsupported
|
hdr.ipv4.ecn = (bit<2>)0; // unsupported
|
||||||
|
|
||||||
hdr.ipv4.ihl = (bit<4>) 5; // internet header length -- needs to be dynamic!
|
hdr.ipv4.ihl = (bit<4>) 5; // internet header length -- needs to be dynamic!?
|
||||||
hdr.ipv4.totalLen = (bit<16>) hdr.ipv6.payload_length + 5; // should probably also dynamic
|
hdr.ipv4.totalLen = (bit<16>) hdr.ipv6.payload_length + 5; // should probably also dynamic
|
||||||
|
|
||||||
hdr.ipv4.identification = (bit<16>) 0; // no support for fragments
|
hdr.ipv4.identification = (bit<16>) 0; // no support for fragments
|
||||||
|
@ -93,25 +93,58 @@ control MyIngress(inout headers hdr,
|
||||||
|
|
||||||
|
|
||||||
/* nat64_prefix is the same as the matching key, but without the mask */
|
/* nat64_prefix is the same as the matching key, but without the mask */
|
||||||
action nat64_static(ipv6_addr_t v6_network, ipv4_addr_t v4_network, ipv6_addr_t nat64_prefix) {
|
action nat64_static(ipv6_addr_t v6_src, ipv4_addr_t v4_dst, ipv6_addr_t nat64_prefix) {
|
||||||
ipv6_addr_t src_offset = hdr.ipv6.src_addr - v6_network;
|
ipv6_addr_t src_offset = hdr.ipv6.src_addr - v6_src;
|
||||||
ipv4_addr_t src = v4_network + (ipv4_addr_t) src_offset;
|
ipv4_addr_t src = v4_dst + (ipv4_addr_t) src_offset;
|
||||||
|
|
||||||
ipv4_addr_t dst = (ipv4_addr_t) (hdr.ipv6.dst_addr - nat64_prefix);
|
ipv4_addr_t dst = (ipv4_addr_t) (hdr.ipv6.dst_addr - nat64_prefix);
|
||||||
|
|
||||||
nat64_generic(src, dst);
|
nat64_generic(src, dst);
|
||||||
|
|
||||||
|
/* fix the protocol specific translations */
|
||||||
|
// switch() ...
|
||||||
}
|
}
|
||||||
|
|
||||||
/* matching key: v4_network specified again */
|
/* matching key: v4_network specified again */
|
||||||
action nat46_static(ipv6_addr_t v6_network, ipv4_addr_t v4_network, ipv6_addr_t nat64_prefix ) {
|
action nat46_static(ipv6_addr_t v6_src, ipv4_addr_t v4_dst, ipv6_addr_t nat64_prefix) {
|
||||||
ipv6_addr_t src = nat64_prefix + (ipv6_addr_t) hdr.ipv4.src_addr;
|
ipv6_addr_t src = nat64_prefix + (ipv6_addr_t) hdr.ipv4.src_addr;
|
||||||
|
|
||||||
ipv4_addr_t dst_offset = hdr.ipv4.dst_addr - v4_network;
|
ipv4_addr_t dst_offset = hdr.ipv4.dst_addr - v4_dst;
|
||||||
ipv6_addr_t dst = v6_network + (ipv6_addr_t) dst_offset;
|
ipv6_addr_t dst = v6_src + (ipv6_addr_t) dst_offset;
|
||||||
|
|
||||||
nat46_generic(src, dst);
|
nat46_generic(src, dst);
|
||||||
|
|
||||||
|
/* fix the protocol specific translations */
|
||||||
|
// switch() ...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table nat64 {
|
||||||
|
key = {
|
||||||
|
hdr.ipv6.src_addr: lpm;
|
||||||
|
hdr.ipv6.dst_addr: lpm;
|
||||||
|
}
|
||||||
|
actions = {
|
||||||
|
controller_debug;
|
||||||
|
nat64_static;
|
||||||
|
NoAction;
|
||||||
|
}
|
||||||
|
size = NAT64_TABLE_SIZE;
|
||||||
|
default_action = controller_debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
table nat46 {
|
||||||
|
key = {
|
||||||
|
hdr.ipv4.src_addr: lpm;
|
||||||
|
hdr.ipv4.dst_addr: lpm;
|
||||||
|
}
|
||||||
|
actions = {
|
||||||
|
controller_debug;
|
||||||
|
nat46_static;
|
||||||
|
NoAction;
|
||||||
|
}
|
||||||
|
size = NAT64_TABLE_SIZE;
|
||||||
|
default_action = controller_debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/********************** ICMP6 ***********************************/
|
/********************** ICMP6 ***********************************/
|
||||||
|
@ -272,8 +305,6 @@ control MyIngress(inout headers hdr,
|
||||||
set_egress_port;
|
set_egress_port;
|
||||||
controller_debug;
|
controller_debug;
|
||||||
controller_reply;
|
controller_reply;
|
||||||
nat64_static;
|
|
||||||
icmp6_neighbor_solicitation;
|
|
||||||
NoAction;
|
NoAction;
|
||||||
}
|
}
|
||||||
size = ROUTING_TABLE_SIZE;
|
size = ROUTING_TABLE_SIZE;
|
||||||
|
@ -287,7 +318,6 @@ control MyIngress(inout headers hdr,
|
||||||
}
|
}
|
||||||
actions = {
|
actions = {
|
||||||
set_egress_port;
|
set_egress_port;
|
||||||
nat46_static;
|
|
||||||
NoAction;
|
NoAction;
|
||||||
}
|
}
|
||||||
size = ROUTING_TABLE_SIZE;
|
size = ROUTING_TABLE_SIZE;
|
||||||
|
@ -297,12 +327,9 @@ control MyIngress(inout headers hdr,
|
||||||
/********************** APPLYING TABLES ***********************************/
|
/********************** APPLYING TABLES ***********************************/
|
||||||
apply {
|
apply {
|
||||||
if(hdr.ipv6.isValid()) {
|
if(hdr.ipv6.isValid()) {
|
||||||
/* FIXME: structure / use .hit to do logic */
|
|
||||||
// ndp_answer.apply();
|
|
||||||
//ndp.apply(); /* flood or if it is us - answer */
|
|
||||||
|
|
||||||
icmp6.apply();
|
icmp6.apply(); /* icmp6 echo, icmp6 ndp */
|
||||||
v6_networks.apply();
|
v6_networks.apply(); /* routing, egress */
|
||||||
}
|
}
|
||||||
if(hdr.ipv4.isValid()) {
|
if(hdr.ipv4.isValid()) {
|
||||||
v4_networks.apply();
|
v4_networks.apply();
|
||||||
|
|
Loading…
Reference in a new issue