summaryrefslogtreecommitdiff
path: root/python/ovs/flow
diff options
context:
space:
mode:
Diffstat (limited to 'python/ovs/flow')
-rw-r--r--python/ovs/flow/kv.py13
-rw-r--r--python/ovs/flow/ofp.py50
-rw-r--r--python/ovs/flow/ofp_act.py85
3 files changed, 102 insertions, 46 deletions
diff --git a/python/ovs/flow/kv.py b/python/ovs/flow/kv.py
index cceb95e43..383d7ee78 100644
--- a/python/ovs/flow/kv.py
+++ b/python/ovs/flow/kv.py
@@ -87,10 +87,11 @@ class KVDecoders(object):
Args:
decoders (dict): Optional; A dictionary of decoders indexed by keyword.
- default (callable): Optional; A decoder used if a match is not found in
- configured decoders. If not provided, the default behavior is to
- try to decode the value into an integer and, if that fails,
- just return the string as-is.
+ default (callable): Optional; A function to use if a match is not
+ found in configured decoders. If not provided, the default behavior
+ is to try to decode the value into an integer and, if that fails,
+ just return the string as-is. The function must accept a the key
+ and the value and return the decoded (key, value) tuple back.
default_free (callable): Optional; The decoder used if a match is not
found in configured decoders and it's a free value (e.g:
a value without a key) Defaults to returning the free value as
@@ -100,7 +101,7 @@ class KVDecoders(object):
def __init__(self, decoders=None, default=None, default_free=None):
self._decoders = decoders or dict()
- self._default = default or decode_default
+ self._default = default or (lambda k, v: (k, decode_default(v)))
self._default_free = default_free or self._default_free_decoder
def decode(self, keyword, value_str):
@@ -126,7 +127,7 @@ class KVDecoders(object):
return keyword, value
else:
if value_str:
- return keyword, self._default(value_str)
+ return self._default(keyword, value_str)
else:
return self._default_free(keyword)
diff --git a/python/ovs/flow/ofp.py b/python/ovs/flow/ofp.py
index 0bc110c57..3d79ed6ad 100644
--- a/python/ovs/flow/ofp.py
+++ b/python/ovs/flow/ofp.py
@@ -243,6 +243,7 @@ class OFPFlow(Flow):
**OFPFlow._fw_action_decoders_args(),
**OFPFlow._control_action_decoders_args(),
**OFPFlow._other_action_decoders_args(),
+ **OFPFlow._instruction_action_decoders_args(),
}
clone_actions = OFPFlow._clone_actions_decoders_args(actions)
actions.update(clone_actions)
@@ -272,6 +273,8 @@ class OFPFlow(Flow):
"pop_vlan": decode_flag,
"strip_vlan": decode_flag,
"push_vlan": decode_default,
+ "pop_mpls": decode_int,
+ "push_mpls": decode_int,
"decap": decode_flag,
"encap": decode_encap,
}
@@ -286,8 +289,8 @@ class OFPFlow(Flow):
"set_mpls_ttl",
"mod_nw_tos",
"mod_nw_ecn",
- "mod_tcp_src",
- "mod_tcp_dst",
+ "mod_tp_src",
+ "mod_tp_dst",
]
return {
"load": decode_load_field,
@@ -299,9 +302,15 @@ class OFPFlow(Flow):
"mod_dl_src": EthMask,
"mod_nw_dst": IPMask,
"mod_nw_src": IPMask,
+ "mod_nw_ttl": decode_int,
+ "mod_vlan_vid": decode_int,
+ "set_vlan_vid": decode_int,
+ "mod_vlan_pcp": decode_int,
+ "set_vlan_pcp": decode_int,
"dec_ttl": decode_dec_ttl,
"dec_mpls_ttl": decode_flag,
"dec_nsh_ttl": decode_flag,
+ "delete_field": decode_field,
"check_pkt_larger": decode_chk_pkt_larger,
**{field: decode_default for field in field_default_decoders},
}
@@ -342,6 +351,14 @@ class OFPFlow(Flow):
)
),
"ct_clear": decode_flag,
+ "fin_timeout": nested_kv_decoder(
+ KVDecoders(
+ {
+ "idle_timeout": decode_time,
+ "hard_timeout": decode_time,
+ }
+ )
+ ),
}
@staticmethod
@@ -382,22 +399,13 @@ class OFPFlow(Flow):
actions.
"""
return {
- "learn": decode_learn(
- {
- **action_decoders,
- "fin_timeout": nested_kv_decoder(
- KVDecoders(
- {
- "idle_timeout": decode_time,
- "hard_timeout": decode_time,
- }
- )
- ),
- }
- ),
+ "learn": decode_learn(action_decoders),
"clone": functools.partial(
decode_exec, KVDecoders(action_decoders)
),
+ "write_actions": functools.partial(
+ decode_exec, KVDecoders(action_decoders)
+ ),
}
@staticmethod
@@ -426,3 +434,15 @@ class OFPFlow(Flow):
)
),
}
+
+ @staticmethod
+ def _instruction_action_decoders_args():
+ """Generate the decoder arguments for instruction actions
+ (see man(7) ovs-actions)."""
+ return {
+ "meter": decode_int,
+ "clear_actions": decode_flag,
+ # write_actions moved to _clone actions
+ "write_metadata": decode_mask(64),
+ "goto_table": decode_int,
+ }
diff --git a/python/ovs/flow/ofp_act.py b/python/ovs/flow/ofp_act.py
index acb16cd9a..c481d6fc7 100644
--- a/python/ovs/flow/ofp_act.py
+++ b/python/ovs/flow/ofp_act.py
@@ -9,9 +9,15 @@ from ovs.flow.decoders import (
decode_flag,
decode_int,
)
-from ovs.flow.kv import nested_kv_decoder, KVDecoders, KeyValue, KVParser
+from ovs.flow.kv import (
+ nested_kv_decoder,
+ KVDecoders,
+ KeyValue,
+ KVParser,
+ ParseError,
+)
from ovs.flow.list import nested_list_decoder, ListDecoders
-from ovs.flow.ofp_fields import field_decoders
+from ovs.flow.ofp_fields import field_decoders, field_aliases
def decode_output(value):
@@ -20,7 +26,9 @@ def decode_output(value):
Does not support field specification.
"""
if len(value.split(",")) > 1:
- return nested_kv_decoder()(value)
+ return nested_kv_decoder(
+ KVDecoders({"port": decode_default, "max_len": decode_int})
+ )(value)
try:
return {"port": int(value)}
except ValueError:
@@ -41,7 +49,17 @@ def decode_controller(value):
except ValueError:
pass
# controller(key[=val], ...)
- return nested_kv_decoder()(value)
+ return nested_kv_decoder(
+ KVDecoders(
+ {
+ "max_len": decode_int,
+ "reason": decode_default,
+ "id": decode_int,
+ "userdata": decode_default,
+ "pause": decode_flag,
+ }
+ )
+ )(value)
def decode_bundle_load(value):
@@ -141,6 +159,12 @@ def decode_field(value):
man page:
http://www.openvswitch.org/support/dist-docs/ovs-actions.7.txt."""
parts = value.strip("]\n\r").split("[")
+ if (
+ parts[0] not in field_decoders.keys()
+ and parts[0] not in field_aliases.keys()
+ ):
+ raise ParseError("Field not supported: {}".format(parts[0]))
+
result = {
"field": parts[0],
}
@@ -269,31 +293,36 @@ def decode_learn(action_decoders):
action decoding.
"""
- def decode_learn_field(decoder, value):
- """Generates a decoder to be used for the 'field' argument of the
- 'learn' action.
-
- The field can hold a value that should be decoded, either as a field,
- or as a the value (see man(7) ovs-actions).
-
- Args:
- decoder (callable): The decoder.
+ def learn_field_decoding_kv(key, value):
+ """Decodes a key, value pair from the learn action.
+ The key must be a decodable field. The value can be either a value
+ in the format defined for the field or another field.
"""
- if value in field_decoders.keys():
- # It's a field
- return value
- else:
- return decoder(value)
-
- learn_field_decoders = {
- field: functools.partial(decode_learn_field, decoder)
- for field, decoder in field_decoders.items()
- }
+ key_field = decode_field(key)
+ try:
+ return key, decode_field(value)
+ except ParseError:
+ return key, field_decoders.get(key_field.get("field"))(value)
+
+ def learn_field_decoding_free(key):
+ """Decodes the free fields found in the learn action.
+ Free fields indicate that the filed is to be copied from the original.
+ In order to express that in a dictionary, return the fieldspec as
+ value. So, the free fild NXM_OF_IP_SRC[], is encoded as:
+ "NXM_OF_IP_SRC[]": {
+ "field": "NXM_OF_IP_SRC"
+ }
+ That way we also ensure the actual free key is correct.
+ """
+ key_field = decode_field(key)
+ return key, key_field
+
learn_decoders = {
**action_decoders,
- **learn_field_decoders,
"idle_timeout": decode_time,
"hard_timeout": decode_time,
+ "fin_idle_timeout": decode_time,
+ "fin_hard_timeout": decode_time,
"priority": decode_int,
"cookie": decode_int,
"send_flow_rem": decode_flag,
@@ -303,4 +332,10 @@ def decode_learn(action_decoders):
"result_dst": decode_field,
}
- return functools.partial(decode_exec, KVDecoders(learn_decoders))
+ learn_decoder = KVDecoders(
+ learn_decoders,
+ default=learn_field_decoding_kv,
+ default_free=learn_field_decoding_free,
+ )
+
+ return functools.partial(decode_exec, learn_decoder)