On 13 Jan 2022, at 12:33, Adrian Moreno wrote:
> On 12/23/21 14:08, Eelco Chaudron wrote:
>> Just some small comments below, and the request to fix up the comments.
>>
>
> Thanks.
>
>>
>>
>> Trying to understand why you have a special ODPFlowFactory class to return
>> an ODPFLow() object from a string?
>> Can you not just add a static method to the ODPFlow class, so it would
>> simply become a matter of calling:
>>
>> ODPFlow.from_string(string, id=id_data)
>>
>> Or probably more OOO is to override the __init__ function of ODPFlow() to
>> take only the string and the id.
>> Don’t think there is a use case to call ODPFlow() with sections and raw.
>>
>
> I'll implement decoders caching via static class variables in the next
> version.
>
>>> +class ODPFlowFactory:
>>> + """Datapath Flow"""
>>> +
>>> + def __init__(self):
>>> + self.info_decoders = self._info_decoders()
>>> + self.match_decoders = self._match_decoders()
>>> + self.action_decoders = self._action_decoders()
>>> +
>>> + def from_string(self, odp_string, id=None):
>>> + """Parse a odp flow string
>>> +
>>> + The string is expected to have the follwoing format:
>>> + [ufid], [match] [flow data] actions:[actions]
>>> +
>>> + Args:
>>> + odp_string (str): a datapath flow string
>>> +
>>> + Returns:
>>> + an ODPFlow instance
>>> + """
>>> +
>>> + sections = []
>>> +
>>> + # If UFID present, parse it and
>>> + ufid_pos = odp_string.find("ufid:")
>>> + if ufid_pos >= 0:
>>> + ufid_string = odp_string[
>>> + ufid_pos : (odp_string[ufid_pos:].find(",") + 1)
>>> + ]
>>> + ufid_parser = KVParser(KVDecoders({"ufid": decode_default}))
>>> + ufid_parser.parse(ufid_string)
>>> + if len(ufid_parser.kv()) != 1:
>>> + raise ValueError("malformed odp flow: %s" % odp_string)
>>> + sections.append(
>>> + Section("ufid", ufid_pos, ufid_string, ufid_parser.kv())
>>> + )
>>> +
>>> + action_pos = odp_string.find("actions:")
>>> + if action_pos < 0:
>>> + raise ValueError("malformed odp flow: %s" % odp_string)
>>> +
>>> + # rest of the string is between ufid and actions
>>> + rest = odp_string[
>>> + (ufid_pos + len(ufid_string) if ufid_pos >= 0 else 0) :
>>> action_pos
>>> + ]
>>> +
>>> + action_pos += 8 # len("actions:")
>>> + actions = odp_string[action_pos:]
>>> +
>>> + field_parts = rest.lstrip(" ").partition(" ")
>>> +
>>> + if len(field_parts) != 3:
>>> + raise ValueError("malformed odp flow: %s" % odp_string)
>>> +
>>> + match = field_parts[0]
>>> + info = field_parts[2]
>>> +
>>> + iparser = KVParser(KVDecoders(self.info_decoders))
>>> + iparser.parse(info)
>>
>> Looking at the two lines above, to me, it looks like the object might not
>> have been defined right (but I’m not an OOO expert).
>> I would have designed it as, KVParser(string, decoders=None), this way you
>> would have a single object initialization, so:
>>
>> parser = KVParser(info, KVDecoders(self.info_decoders))
>>
>> Also because the parse() method does not allow re-use of the object, meaning
>> parse another string with the same instance.
>> Or was there a specific reason to split this in two stages?
>>
>
> It's a remainder of a previous design. Right now I agree it doesn't make
> sense. I'll change it in the next version.
>
>>> + isection = Section(
>>> + name="info",
>>> + pos=odp_string.find(info),
>>> + string=info,
>>> + data=iparser.kv(),
>>> + )
>>> + sections.append(isection)
>>> +
>>> + mparser = KVParser(KVDecoders(self.match_decoders))
>>> + mparser.parse(match)
>>> + msection = Section(
>>> + name="match",
>>> + pos=odp_string.find(match),
>>> + string=match,
>>> + data=mparser.kv(),
>>> + )
>>> + sections.append(msection)
>>> +
>>> + aparser = KVParser(
>>> + KVDecoders(self.action_decoders,
>>> default_free=decode_free_output)
>>> + )
>>> + aparser.parse(actions)
>>> + asection = Section(
>>> + name="actions",
>>> + pos=action_pos,
>>> + string=actions,
>>> + data=aparser.kv(),
>>> + is_list=True,
>>> + )
>>> + sections.append(asection)
>>> +
>>> + return ODPFlow(sections, odp_string, id)
>>> +
>>> + @classmethod
>>
>> Any reason why all of these are @classmethod, and not @staticmethod, as they
>> do not seem to need a reference to self?
>> Guess this is also true in some of the previous patches, but I did not
>> notice ;)
>
> Right.
>
> [...]
>>> +
>>> + @classmethod
>>> + def _field_decoders(cls):
>>> + return {
>>> + "skb_priority": Mask32,
>>> + "skb_mark": Mask32,
>>> + "recirc_id": decode_int,
>>> + "dp_hash": Mask32,
>>> + "ct_state": decode_default, # TODO: Parse flags
>>
>> Guess we might want to fix this before the merge?
>>
>
> Well, I've left it initially to confirm whether there is a strong need for
> this. Decoding ct_state with a integer allows you to set any ct_state, only
> you have to do it using the hexadecimal representation.
>
> Do you think we'll want to use string representation of flags? Same goes for
> other flags like tcp_flags.
Good question!
Here is a dump with -m (ovs-appctl dpctl/dump-flows -m):
ufid:97fc770e-2233-4b72-bfbc-7dbf3870ddf5,
recirc_id(0x1),dp_hash(0/0),skb_priority(0/0),in_port(ovsp0),skb_mark(0/0),ct_state(0x1/0x1),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),eth(src=00:00:00:00:00:00/00:00:00:00:00:00,dst=00:00:00:00:00:00/00:00:00:00:00:00),eth_type(0x0800,ipv4(src=0.0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=6,tos=0/0,ttl=0/0,frag=no),tcp(src=0/0,dst=0/0),tcp_flags(0/0),
packets:0, bytes:0, used:never, dp:ovs,
actions:ct(commit,zone=1,mark=0x5/0x5,label=0x5/0x5),ct(commit,zone=2),ovs-p1
And one without:
recirc_id(0x1),in_port(2),ct_state(+new),eth(),eth_type(0x0800),ipv4(proto=6,frag=no),
packets:0, bytes:0, used:never,
actions:ct(commit,zone=1,mark=0x5/0x5,label=0x5/0x5),ct(commit,zone=2),3
So which one do we need!? Guess we need to be able to decode both, depending on
the input? Ping me offline if we need a quick brainstorming session.
> [...]
>>> +def decode_geneve(mask, value):
>>> + """
>>> + Decode geneve options. Used for both
>>> tnl_push(header(geneve(options())))
>>> + action and tunnel(geneve()) match.
>>> +
>>> + It has the following format:
>>> +
>>> + {class=0xffff,type=0x80,len=4,0xa}
>>> +
>>> + Args:
>>> + mask (bool): Whether masking is supported
>>> + value (str): The value to decode
>>> + """
>>> + if mask:
>>
>> Create some consistency around the ending of doctext and the first line of
>> code (in all patches).
>> Sometimes you have an empty line, like in decode_tnl_gre below, and
>> sometimes not like here.
>>
>
> For some reason I was expecting my formatter to do that for me, but I guess
> it's not... Sure, I'll double check.
>
> --
> Adrián Moreno
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev