Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding ipv6 support and del/modify to p4runtime_lib #326

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions utils/p4runtime_lib/convert.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/usr/bin/python2
# Copyright 2017-present Open Networking Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -35,15 +36,25 @@ def decodeMac(encoded_mac_addr):
return ':'.join(s.encode('hex') for s in encoded_mac_addr)

ip_pattern = re.compile('^(\d{1,3}\.){3}(\d{1,3})$')
ipv6_pattern = re.compile('^(?:(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){6})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:::(?:(?:(?:[0-9a-fA-F]{1,4})):){5})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})))?::(?:(?:(?:[0-9a-fA-F]{1,4})):){4})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,1}(?:(?:[0-9a-fA-F]{1,4})))?::(?:(?:(?:[0-9a-fA-F]{1,4})):){3})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,2}(?:(?:[0-9a-fA-F]{1,4})))?::(?:(?:(?:[0-9a-fA-F]{1,4})):){2})(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,3}(?:(?:[0-9a-fA-F]{1,4})))?::(?:(?:[0-9a-fA-F]{1,4})):)(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,4}(?:(?:[0-9a-fA-F]{1,4})))?::)(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,5}(?:(?:[0-9a-fA-F]{1,4})))?::)(?:(?:[0-9a-fA-F]{1,4})))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]{1,4})):){0,6}(?:(?:[0-9a-fA-F]{1,4})))?::))))$')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if using regex pattern to match IPv6 addresses is a good idea because the regex itself is complex and it would be very difficult to debug. An alternative solution could be:

diff --git a/utils/p4runtime_lib/convert.py b/utils/p4runtime_lib/convert.py
index f6580e0..ca452ee 100644
--- a/utils/p4runtime_lib/convert.py
+++ b/utils/p4runtime_lib/convert.py
@@ -35,14 +35,17 @@ def decodeMac(encoded_mac_addr):
     return ':'.join(s.encode('hex') for s in encoded_mac_addr)
 
 ip_pattern = re.compile('^(\d{1,3}\.){3}(\d{1,3})$')
-def matchesIPv4(ip_addr_string):
-    return ip_pattern.match(ip_addr_string) is not None
-
-def encodeIPv4(ip_addr_string):
-    return socket.inet_aton(ip_addr_string)
-
-def decodeIPv4(encoded_ip_addr):
-    return socket.inet_ntoa(encoded_ip_addr)
+def encodeIP(ip_addr_string):
+    if ip_pattern.match(ip_addr_string):
+        return socket.inet_pton(socket.AF_INET, ip_addr_string)
+    return socket.inet_pton(socket.AF_INET6, ip_addr_string)
+
+def decodeIP(encoded_ip_addr):
+    if len(encoded_ip_addr) == 4:
+        return socket.inet_ntop(socket.AF_INET, encoded_ip_addr)
+    if len(encoded_ip_addr) == 16:
+        return socket.inet_ntop(socket.AF_INET6, encoded_ip_addr)
+    raise Exception("Encoded IP address has invalid length %d" % len(encoded_ip_addr))
 
 def bitwidthToBytes(bitwidth):
     return int(math.ceil(bitwidth / 8.0))
@@ -66,11 +69,12 @@ def encode(x, bitwidth):
     if type(x) == str:
         if matchesMac(x):
             encoded_bytes = encodeMac(x)
-        elif matchesIPv4(x):
-            encoded_bytes = encodeIPv4(x)
         else:
-            # Assume that the string is already encoded
-            encoded_bytes = x
+            try:
+                encoded_bytes = encodeIP(x)
+            except socket.error:
+                # Assume that the string is already encoded
+                encoded_bytes = x
     elif type(x) == int:
         encoded_bytes = encodeNum(x, bitwidth)
     else:

def matchesIPv4(ip_addr_string):
return ip_pattern.match(ip_addr_string) is not None
# enable ipv6
def matchesIPv6(ip_addr_string):
return ipv6_pattern.match(ip_addr_string) is not None

def encodeIPv4(ip_addr_string):
return socket.inet_aton(ip_addr_string)

def encodeIPv6(ip_addr_string):
return socket.inet_pton(socket.AF_INET6,ip_addr_string)

def decodeIPv4(encoded_ip_addr):
return socket.inet_ntoa(encoded_ip_addr)

def decodeIPv6(encoded_ip_addr):
return socket.inet_ntop(encoded_ip_addr)

def bitwidthToBytes(bitwidth):
return int(math.ceil(bitwidth / 8.0))

Expand All @@ -68,9 +79,13 @@ def encode(x, bitwidth):
encoded_bytes = encodeMac(x)
elif matchesIPv4(x):
encoded_bytes = encodeIPv4(x)
elif matchesIPv6(x):
encoded_bytes = encodeIPv6(x)
else:
# Assume that the string is already encoded
encoded_bytes = x
# using encode IPV6
# encoded_bytes = encodeIPv6(x)
elif type(x) == int:
encoded_bytes = encodeNum(x, bitwidth)
else:
Expand Down Expand Up @@ -104,6 +119,10 @@ def encode(x, bitwidth):
assert(not matchesIPv4('1000.0.0.1'))
assert(not matchesIPv4('10001'))

assert(matchesIPv6('::1234'))
assert(matchesIPv6('1234::'))
assert(matchesIPv6('1234::1234'))

assert(encode(mac, 6 * 8) == enc_mac)
assert(encode(ip, 4 * 8) == enc_ip)
assert(encode(num, 5 * 8) == enc_num)
Expand Down
27 changes: 27 additions & 0 deletions utils/p4runtime_lib/switch.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,33 @@ def WriteTableEntry(self, table_entry, dry_run=False):
print "P4Runtime Write:", request
else:
self.client_stub.Write(request)
# Modify
def ModifyTableEntry(self, table_entry, dry_run=False):
request = p4runtime_pb2.WriteRequest()
request.device_id = self.device_id
request.election_id.low = 1
update = request.updates.add()
# Assign Modify Type for it
update.type = p4runtime_pb2.Update.MODIFY
update.entity.table_entry.CopyFrom(table_entry)
if dry_run:
print "P4Runtime Modify: ", request
else:
self.client_stub.Write(request)

# Delete
def DeleteTableEntry(self, table_entry, dry_run=False):
request = p4runtime_pb2.WriteRequest()
request.device_id = self.device_id
request.election_id.low = 1
update = request.updates.add()
# Assign DELETE Type for it
update.type = p4runtime_pb2.Update.DELETE
update.entity.table_entry.CopyFrom(table_entry)
if dry_run:
print "P4Runtime Delete: ", request
else:
self.client_stub.Write(request)

def ReadTableEntries(self, table_id=None, dry_run=False):
request = p4runtime_pb2.ReadRequest()
Expand Down