summaryrefslogtreecommitdiffstats
path: root/extras
AgeCommit message (Expand)AuthorFilesLines
2019-02-19VOM: no assert on interface mac setNeale Ranns2-2/+3
2019-02-14deb-pkg: Add libvom package supportMohsin Kazmi1-11/+5
2019-02-13vom: Add support for vtr in xconnectMohsin Kazmi11-138/+294
2019-02-13VOM: neighbour API flagsNeale Ranns8-25/+131
2019-02-05VOM: vxlan_tunnel equals operatorNeale Ranns2-1/+12
2019-01-31Update version (19.01) for API changes scriptAndrew Yourtchenko1-2/+2
2019-01-31extras: vfctl script - bind VF to vfio-pci after VF is createdDamjan Marion1-0/+10
2019-01-30Use IP and MAC API types for neighborsNeale Ranns7-29/+56
2019-01-25deprecate tapcliDamjan Marion5-7/+0
2019-01-22GBP: Sclass to src-epg conversionsNeale Ranns8-16/+96
2019-01-22VOM: GBP bridge domain flagsNeale Ranns8-23/+69
2019-01-17VOM: ip-mroute inspect register handler fixNeale Ranns1-1/+2
2019-01-17DOC ONLY: wireshark dissector upstreamedDave Barach1-84/+0
2019-01-16DOC ONLY: update readme.mdDave Barach3-469/+28
2019-01-10vpp_config: Rework for Python2/3 compatibility.Paul Vinciguerra12-406/+554
2019-01-10VOM: IP route ECMP supportNeale Ranns3-24/+56
2019-01-09Use the official libpcap file typeDave Barach1-1/+1
2019-01-07VOM: mroutesNeale Ranns12-117/+1306
2019-01-04libmemif: fix incorrect write leading to memory corruptionKoichiro Den1-3/+3
2019-01-04VPP-1525: additional fixes for strings in JapiMichal Cmarada5-21/+104
2018-12-24GBP: fix dump and VOM populateNeale Ranns12-205/+96
2018-12-23VOM: statsNeale Ranns7-47/+87
2018-12-21GBP: add allowed ethertypes to contractsNeale Ranns6-93/+138
2018-12-19VOM: stats fixesNeale Ranns6-83/+88
2018-12-19VOM: VXLAN-GBP command fixesNeale Ranns3-6/+9
2018-12-19VOM: GBP-bridge-domain fixNeale Ranns2-14/+8
2018-12-19Allow the user to select master or release during the installjdenisco3-51/+38
2018-12-18VAPI/VOM: Removing legacy stats tests, add string type.Ole Troan2-9/+10
2018-12-18Build changes required for Fedora and CentOSThomas F Herbert1-7/+8
2018-12-18PAPI: Add MACAddress object wrapper for vl_api_mac_address_tOle Troan5-13/+9
2018-12-18Remove autotools files from extras/libmemifMauro Sardara3-117/+0
2018-12-17VOM: IGMP only supports IPv4Neale Ranns7-19/+73
2018-12-17libmemif: fix possible segfault on memif_get_detailsKoichiro Den1-31/+28
2018-12-17Added CMake building system for libmemifmsardara12-69/+367
2018-12-16VOM: fixes for statsNeale Ranns4-10/+9
2018-12-13API: Use string type instead of u8.Ole Troan15-40/+122
2018-12-13vom: Add support for new statsMohsin Kazmi13-266/+990
2018-12-12VOM: vxlan-tunnel takes egress interface for multicastNeale Ranns6-17/+49
2018-12-10VOM: vxlan-gbpNeale Ranns11-100/+522
2018-12-07vpp_if_stats: Fixing a bug in getting vpp interfaces indexesKoren Lev2-10/+10
2018-12-07vom: Fix the api type definitionMohsin Kazmi1-2/+4
2018-12-06API: Change ip4_address and ip6_address to use type alias.Ole Troan6-54/+19
2018-12-06Update japi to support type aliasesMichal Cmarada5-32/+126
2018-12-05VOM: interface event structNeale Ranns7-5/+72
2018-11-30Metadata / opaque formatting belongs in vppDave Barach1-781/+178
2018-11-29VOM: missing GBP symbolNeale Ranns1-1/+2
2018-11-29VOM: deprecate TAP add ip-punt redirect dumpNeale Ranns13-297/+174
2018-11-29GBP: l3-out subnetsNeale Ranns7-1/+685
2018-11-29VPP-1507: Added binary api to dump configured ip_punt_redirectPavel Kotucek1-8/+7
2018-11-29API: Add support for type aliasesOle Troan1-0/+7
class="n">net_to_host_function self.is_swap_needed = host_to_net_function and net_to_host_function class SimpleType(Type): def __init__(self, name, java_name, jni_signature, jni_type, jni_accessor, host_to_net_function=None, net_to_host_function=None): super(SimpleType, self).__init__( name=name, java_name=java_name, java_name_fqn=java_name, jni_signature=jni_signature, jni_type=jni_type, jni_accessor=jni_accessor, host_to_net_function=host_to_net_function, net_to_host_function=net_to_host_function ) self.vpp_name = name def get_host_to_net_function(self, host_ref_name, net_ref_name): return "%s = %s(%s)" % (net_ref_name, self.host_to_net_function, host_ref_name) def __str__(self): return "SimpleType{name:%s, java_name:%s}" % (self.name, self.java_name) # TODO(VPP-1187): add array host to net functions to reduce number of members and simplify JNI generation class Array(Type): def __init__(self, base_type): super(Array, self).__init__( name=base_type.name + _ARRAY_SUFFIX, java_name=base_type.java_name + _ARRAY_SUFFIX, java_name_fqn=base_type.java_name_fqn + _ARRAY_SUFFIX, jni_signature="[%s" % base_type.jni_signature, jni_type="%sArray" % base_type.jni_type, jni_accessor="Object", host_to_net_function=base_type.host_to_net_function, net_to_host_function=base_type.net_to_host_function ) self.base_type = base_type def get_host_to_net_function(self, host_ref_name, net_ref_name): return self.base_type.get_host_to_net_function(host_ref_name, net_ref_name) def __str__(self): return "Array{name:%s, java_name:%s}" % (self.name, self.java_name) class Class(Type): def __init__(self, name, crc, fields, definition, plugin_name): _java_name = _underscore_to_camelcase_upper(name) super(Class, self).__init__( name=name, java_name=_java_name, java_name_fqn="io.fd.vpp.jvpp.%s.types.%s" % (plugin_name, _java_name), jni_signature="Lio/fd/vpp/jvpp/%s/types/%s;" % (plugin_name, _java_name), jni_type="jobject", jni_accessor="Object", host_to_net_function="_host_to_net_%s" % name, net_to_host_function="_net_to_host_%s" % name ) self.crc = crc self.fields = fields self.doc = _message_to_javadoc(definition) self.java_name_lower = _underscore_to_camelcase_lower(name) self.vpp_name = "%s%s%s" % (_VPP_TYPE_PREFIX, name, _VPP_TYPE_SUFFIX) # Fully qualified class name used by FindClass function, see: # https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#FindClass self.jni_name = "io/fd/vpp/jvpp/%s/types/%s" % (plugin_name, _java_name) def get_host_to_net_function(self, host_ref_name, net_ref_name): return "_host_to_net_%s(env, %s, &(%s))" % (self.name, host_ref_name, net_ref_name) class Field(object): def __init__(self, name, field_type, array_len=None, array_len_field=None): self.name = name self.java_name = _underscore_to_camelcase_lower(name) self.type = field_type self.array_len = array_len self.array_len_field = array_len_field def __str__(self): return "Field{name:%s, java_name:%s, type:%s}" % (self.name, self.java_name, self.type) class Message(object): def __init__(self, name, crc, fields, definition): self.name = name self.java_name_upper = _underscore_to_camelcase_upper(name) self.java_name_lower = _underscore_to_camelcase_lower(name) self.crc = crc[2:] self.fields = fields self.has_fields = fields != [] self.doc = _message_to_javadoc(definition) def __str__(self): return "Message{name:%s, java_name:%s, crc:%s, fields:%s}" % ( self.name, self.java_name_upper, self.crc, self.fields) class Event(Message): def __init__(self, name, crc, fields, definition): super(Event, self).__init__(name, crc, fields, definition) class Request(Message): def __init__(self, name, reply, crc, fields, definition): super(Request, self).__init__(name, crc, fields, definition) self.reply = reply self.reply_java = _underscore_to_camelcase_upper(reply) def __str__(self): return "Request{name:%s, reply:%s, crc:%s, fields:%s}" % (self.name, self.reply, self.crc, self.fields) class Reply(Message): def __init__(self, name, request, crc, fields, definition): super(Reply, self).__init__(name, crc, fields, definition) self.request = request self.request_java = _underscore_to_camelcase_upper(request) def __str__(self): return "Reply{name:%s, request:%s, crc:%s, fields:%s}" % (self.name, self.request, self.crc, self.fields) class Dump(Message): def __init__(self, name, details, crc, fields, definition): super(Dump, self).__init__(name, crc, fields, definition) self.details = details self.reply_java = _underscore_to_camelcase_upper(details) def __str__(self): return "Dump{name:%s, details:%s, crc:%s, fields:%s}" % (self.name, self.details, self.crc, self.fields) class Details(Message): def __init__(self, name, dump, crc, fields, definition): super(Details, self).__init__(name, crc, fields, definition) self.dump = dump self.request_java = _underscore_to_camelcase_upper(dump) def __str__(self): return "Details{name:%s, dump:%s, crc:%s, fields:%s}" % (self.name, self.dump, self.crc, self.fields) def is_retval(field): return field.name == u'retval' def is_array(field): return field.array_len is not None def is_request(msg): return hasattr(msg, 'reply') def is_reply(msg): return hasattr(msg, 'request') def is_dump(msg): return hasattr(msg, 'details') def is_details(msg): return hasattr(msg, 'dump') def is_event(msg): return isinstance(msg, Event) def is_control_ping(msg): return msg.name == u'control_ping' def is_control_ping_reply(msg): return msg.name == u'control_ping_reply' class JVppModel(object): def __init__(self, logger, json_api_files, plugin_name): self.logger = logger # TODO(VPP-1188): provide json_file_by_definition map to improve javadoc self.json_api_files = json_api_files self.plugin_package = BASE_PACKAGE + "." + plugin_name self.plugin_name = plugin_name self.plugin_java_name = _underscore_to_camelcase_upper(plugin_name) self._load_json_files(json_api_files) self._parse_types() self._parse_services() self._parse_messages() self._validate_messages() def _load_json_files(self, json_api_files): self._enums = [] self._types = [] self._messages = [] self._services = {} for file_name in json_api_files: with open(file_name) as f: j = json.load(f) self._enums.extend(j['enums']) self._types.extend(j['types']) self._messages.extend(j['messages']) self._services.update(j['services']) def _parse_types(self): # Mapping according to: # http://docs.oracle.com/javase/7/do+'[]'cs/technotes/guides/jni/spec/types.html # and # https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#Get_type_Field_routines # # Unsigned types are converted to signed java types that have the same size. # It is the API user responsibility to interpret them correctly. self._types_by_name = OrderedDict({ 'u8': SimpleType('u8', 'byte', 'B', 'jbyte', 'Byte'), 'i8': SimpleType('i8', 'byte', 'B', 'jbyte', 'Byte'), 'u16': SimpleType('u16', 'short', 'S', 'jshort', 'Short', host_to_net_function='clib_host_to_net_u16', net_to_host_function='clib_net_to_host_u16'), 'i16': SimpleType('i16', 'short', 'S', 'jshort', 'Short', host_to_net_function='clib_host_to_net_i16', net_to_host_function='clib_net_to_host_i16'), 'u32': SimpleType('u32', 'int', 'I', 'jint', 'Int', host_to_net_function='clib_host_to_net_u32', net_to_host_function='clib_net_to_host_u32'), 'i32': SimpleType('i32', 'int', 'I', 'jint', 'Int', host_to_net_function='clib_host_to_net_i32', net_to_host_function='clib_net_to_host_i32'), 'u64': SimpleType('u64', 'long', 'J', 'jlong', 'Long', host_to_net_function='clib_host_to_net_u64', net_to_host_function='clib_net_to_host_u64'), 'i64': SimpleType('i64', 'long', 'J', 'jlong', 'Long', host_to_net_function='clib_host_to_net_i64', net_to_host_function='clib_net_to_host_i64'), 'f64': SimpleType('f64', 'double', 'D', 'jdouble', 'Double') }) for n, t in self._types_by_name.items(): self._types_by_name[n + _ARRAY_SUFFIX] = Array(t) for json_type in self._types: name = json_type[0] definition = json_type[1:] _type = self._parse_type(name, definition) self._types_by_name[name] = _type self._types_by_name[name + _ARRAY_SUFFIX] = Array(_type) self.types = self._types_by_name.values() def _parse_type(self, name, definition): self.logger.debug("Parsing type %s: %s", name, definition) crc, fields = self._parse_fields(definition) return Class(name, crc, fields, definition, self.plugin_name) def _parse_services(self): self._dumps_by_details = {} self._requests_by_reply = {} for name, service in self._services.iteritems(): if _is_stream(service): self._dumps_by_details[service['reply']] = name else: self._requests_by_reply[service['reply']] = name def _parse_messages(self): # Preserve ordering from JSON file to make debugging easier. self._messages_by_name = OrderedDict() for msg in self._messages: try: name = msg[0] definition = msg[1:] self._messages_by_name[name] = self._parse_message(name, definition) except ParseException as e: self.logger.warning("Failed to parse message %s: %s. Skipping message.", name, e) def _parse_message(self, name, definition): self.logger.debug("Parsing message %s: %s", name, definition) crc, fields = self._parse_fields(definition) if name in self._services: service = self._services[name] reply = service['reply'] if _is_stream(service): return Dump(name, reply, crc, filter(_is_request_field, fields), definition) if reply: return Request(name, reply, crc, filter(_is_request_field, fields), definition) else: return Event(name, crc, filter(_is_request_field, fields), definition) elif name in self._requests_by_reply: return Reply(name, self._requests_by_reply[name], crc, filter(_is_reply_field, fields), definition) elif name in self._dumps_by_details: return Details(name, self._dumps_by_details[name], crc, filter(_is_reply_field, fields), definition) else: # TODO: some messages like combined_counters are not visible in the services. # Throw exception instead (requires fixing vppagigen). return Event(name, crc, filter(_is_request_field, fields), definition) def _parse_fields(self, definition): crc = None fields = [] for item in definition: if type(item) == dict and 'crc' in item: crc = item['crc'] else: fields.append(self._parse_field(item, fields)) if not crc: raise ParseException("CRC was not defined for %s" % definition) return crc, fields def _parse_field(self, field, fields): type_name = _extract_type_name(field[0]) if type_name in self._types_by_name: if len(field) > 2: # Array field array_len_field = None if len(field) == 4: for f in fields: if f.name == field[3]: array_len_field = f if not array_len_field: raise ParseException("Could not find field %s declared as length of array %s", field[3], field[1]) return Field(field[1], self._types_by_name[type_name + _ARRAY_SUFFIX], field[2], array_len_field) else: return Field(field[1], self._types_by_name[type_name]) else: raise ParseException("Unknown field type %s" % field) def _validate_messages(self): """ In case if message A is known to be reply for message B, and message B was not correctly parsed, remove message A from the set of all messages. """ to_be_removed = [] messages = self._messages_by_name for name, msg in messages.iteritems(): if (is_request(msg) and msg.reply not in messages) \ or (is_reply(msg) and msg.request not in messages) \ or (is_dump(msg) and msg.details not in messages) \ or (is_details(msg) and msg.dump not in messages): to_be_removed.append(name) for name in to_be_removed: del messages[name] self.messages = self._messages_by_name.values() _ARRAY_SUFFIX = '[]' def _underscore_to_camelcase_upper(name): return name.title().replace("_", "") def _underscore_to_camelcase_lower(name): name = name.title().replace("_", "") return name[0].lower() + name[1:] def _message_to_javadoc(message_definition): """ Converts JSON message definition to javadoc """ formatted_message = pprint.pformat(message_definition, indent=4, width=120, depth=None) return " * " + formatted_message.replace("\n", "\n * ") def _is_stream(service): """ Checks if service represents stream, e.g.: "ip_address_dump": { "reply": "ip_address_details", "stream": true } :param service: JSON definition of service :return: value assigned to "stream" or None """ return "stream" in service def _extract_type_name(name): if name.startswith(_VPP_TYPE_PREFIX) and name.endswith(_VPP_TYPE_SUFFIX): return name[len(_VPP_TYPE_PREFIX): - len(_VPP_TYPE_SUFFIX)] return name _VPP_TYPE_PREFIX = "vl_api_" _VPP_TYPE_SUFFIX = "_t" def _is_request_field(field): # Skip fields that are hidden to the jvpp user (handled by JNI layer) return field.name not in {'_vl_msg_id', 'client_index', 'context'} def _is_reply_field(field): # Skip fields that are hidden to the jvpp user: # _vl_msg_id is handled at JNI layer, # Unlike in the request case, context is visible to allow matching replies with requests at Java layer. return field.name not in {'_vl_msg_id'}