aboutsummaryrefslogtreecommitdiffstats
path: root/dpdk
AgeCommit message (Expand)AuthorFilesLines
2017-03-31dpdk: add support for Mellanox ConnectX-5 devicesDamjan Marion9-1/+1703
2017-03-22dpdk: fix plugin linking with sw crypto librariesSergio Gonzalez Monroy1-19/+26
2017-02-28dpdk: retire support for dpdk 16.07Damjan Marion12-41832/+0
2017-02-21cryptodev: Automatically download and build ISA-L Crypto libraryRadu Nicolau1-1/+20
2017-02-20dpdk: updated build to automatically download Intel(R) Multi-Buffer Crypto fo...Radu Nicolau1-0/+22
2017-02-17dpdk: bump to DPDK 17.02Damjan Marion1-2/+3
2017-02-07Multiple platofrm support for dpdk/Makefile, fix optimizationsDamjan Marion1-27/+25
2017-02-02ENIC driver patch to fix MAC address add and removeSteve Shin2-1/+123
2017-01-31Bump up PKG_SUFFIX to vpp3Steve Shin1-1/+1
2017-01-30This patch fixes a bug in replaying MAC address to the hardwareSteve Shin1-0/+83
2017-01-27dpdk: rework cryptodev ipsec build and setupSergio Gonzalez Monroy1-5/+5
2017-01-21Fix cosmetic issue in dpdk/MakefileDamjan Marion1-1/+1
2017-01-20Add dpdk development packagingDamjan Marion8-32/+213
2017-01-02dpdk: do not build igb_uio moduleDamjan Marion1-0/+1
2016-12-26dpdk: Add support for Mellanox ConnectX-4 devicesDamjan Marion1-1/+3
2016-11-30dpdk patch: virtio: tx with can_push when VERSION_1 is setPierre Pfister1-0/+38
2016-11-28dpdk: add ipsec cryptodev supportSergio Gonzalez Monroy1-0/+4
2016-11-24dpdk: remove old patchesDamjan Marion65-50996/+0
2016-11-23dpdk: switch to 16.11Damjan Marion2-2/+1
2016-11-14dpdk: add build support for DPDK 16.11 releaseDamjan Marion1-1/+1
2016-11-09dpdk: bump to 16.11-rc3 releaseDamjan Marion1-1/+1
2016-10-26dpdk: enable building with dpdk 16.11-rc1Damjan Marion1-0/+1
2016-09-12DPDK virtio patch: Enable indirect descriptor featuresPierre Pfister1-0/+34
2016-08-25VPP-345: pull in upstream checksum patch for ICMP packetsSean Chandler1-0/+18
2016-08-12VPP: NXP dpaa2 platform porting to dpdk-16.07Sachin1-0/+40106
2016-08-11Rename DPDK-16.07 patch file from 0007... to 0008... to avoid conflictJohn Lo1-0/+0
2016-08-10DPDK: Fix a crash in igb_uio driver when the device is removed.Ray Kinsella1-0/+38
2016-08-10Temporarily disable unthrottled log message from DPDK 16.07John Lo1-0/+26
2016-08-09dpdk: allow applications to override rte delayRay1-0/+43
2016-08-09DPDK: adding patch to init ptype in vmxnet3, e1000 and virtio PMDsRay1-0/+70
2016-08-08DPDK: adding patch to revert ptype change to ixgbe vpmdRay1-0/+133
2016-08-04ENIC driver patch for PKT_RX_VLAN_PKT packet flag backward compatibilityJohn Lo1-0/+42
2016-08-03VPP-180 Clean up multi-socket / multi-chunk mempool discoveryDave Barach3-2/+1
2016-08-02VPP: Fixed dpdk-16.07 BAD checksum errorSachin1-1/+1
2016-07-29enic: fix bug introduced with scatter rxShesha Sreenivasamurthy1-0/+24
2016-07-22Add DPDK 16.07 support (rc3 based)Damjan Marion3-1/+1322
2016-07-20ENIC driver update to init mbuf data offset to RTE_PKTMBUF_HEADROOMJohn Lo1-0/+47
2016-07-16Add DPDK patches for i40e vPMD (ptype and ip checksum offload)Damjan Marion2-0/+1298
2016-07-12ENIC driver update to allow bonded interface admin down/up to pass trafficJohn Lo2-0/+79
2016-07-05ENIC driver patches to address various issuesJohn Lo10-0/+741
2016-07-02Enable PCI extended tags in the DPDK configDamjan Marion1-1/+3
2016-06-17NXP DPAA2 Poll Mode Driver Support in DPDKSachin1-0/+40404
2016-06-09VPP-106: fix performance hit due to unprefetched data readDave Barach1-41/+0
2016-06-07Rebase DPDK patchesDamjan Marion7-100/+139
2016-06-05dpdk: download from dpdk.orgThomas Monjalon1-6/+6
2016-06-02VPP-106: Patch e40i driver to support VLAN sub-interfaceJohn Lo1-0/+41
2016-05-28VPP-96 ENID driver update for rx of jumbo pkts using muliple mbuf'sJohn Lo2-0/+798
2016-05-19Add support for multiple microarchitectures in single binaryDamjan Marion1-1/+2
2016-05-17dpdk/Makefile - Allow dpdk target to be set according to the platformChristophe Fontaine1-1/+10
2016-05-07Switch to using nexus.fd.io for dpdk tarballEd Warnicke1-1/+1
bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
#!/usr/bin/env python2

import argparse
import os
import sys
import logging
from vapi_json_parser import Field, Struct, Enum, Union, Message, JsonParser,\
    SimpleType, StructType


class CField(Field):
    def get_c_def(self):
        if self.len is not None:
            return "%s %s[%d]" % (self.type.get_c_name(), self.name, self.len)
        else:
            return "%s %s" % (self.type.get_c_name(), self.name)

    def get_swap_to_be_code(self, struct, var):
        if self.len is not None:
            if self.len > 0:
                return "do { unsigned i; for (i = 0; i < %d; ++i) { %s } }"\
                    " while(0);" % (
                        self.len,
                        self.type.get_swap_to_be_code(struct, "%s[i]" % var))
            else:
                if self.nelem_field.needs_byte_swap():
                    nelem_field = "%s(%s%s)" % (
                        self.nelem_field.type.get_swap_to_host_func_name(),
                        struct, self.nelem_field.name)
                else:
                    nelem_field = "%s%s" % (struct, self.nelem_field.name)
                return (
                    "do { unsigned i; for (i = 0; i < %s; ++i) { %s } }"
                    " while(0);" %
                    (nelem_field, self.type.get_swap_to_be_code(
                        struct, "%s[i]" % var)))
        return self.type.get_swap_to_be_code(struct, "%s" % var)

    def get_swap_to_host_code(self, struct, var):
        if self.len is not None:
            if self.len > 0:
                return "do { unsigned i; for (i = 0; i < %d; ++i) { %s } }"\
                    " while(0);" % (
                        self.len,
                        self.type.get_swap_to_host_code(struct, "%s[i]" % var))
            else:
                # nelem_field already swapped to host here...
                return (
                    "do { unsigned i; for (i = 0; i < %s%s; ++i) { %s } }"
                    " while(0);" %
                    (struct, self.nelem_field.name,
                     self.type.get_swap_to_host_code(
                         struct, "%s[i]" % var)))
        return self.type.get_swap_to_host_code(struct, "%s" % var)

    def needs_byte_swap(self):
        return self.type.needs_byte_swap()


class CStruct(Struct):
    def get_c_def(self):
        return "\n".join([
            "typedef struct __attribute__((__packed__)) {\n%s;" % (
                ";\n".join(["  %s" % x.get_c_def()
                            for x in self.fields])),
            "} %s;" % self.get_c_name()])


class CSimpleType (SimpleType):

    swap_to_be_dict = {
        'i16': 'htobe16', 'u16': 'htobe16',
        'i32': 'htobe32', 'u32': 'htobe32',
        'i64': 'htobe64', 'u64': 'htobe64',
    }

    swap_to_host_dict = {
        'i16': 'be16toh', 'u16': 'be16toh',
        'i32': 'be32toh', 'u32': 'be32toh',
        'i64': 'be64toh', 'u64': 'be64toh',
    }

    def get_c_name(self):
        return self.name

    def get_swap_to_be_func_name(self):
        return self.swap_to_be_dict[self.name]

    def get_swap_to_host_func_name(self):
        return self.swap_to_host_dict[self.name]

    def get_swap_to_be_code(self, struct, var, cast=None):
        x = "%s%s" % (struct, var)
        return "%s = %s%s(%s);" % (x,
                                   "(%s)" % cast if cast else "",
                                   self.get_swap_to_be_func_name(), x)

    def get_swap_to_host_code(self, struct, var, cast=None):
        x = "%s%s" % (struct, var)
        return "%s = %s%s(%s);" % (x,
                                   "(%s)" % cast if cast else "",
                                   self.get_swap_to_host_func_name(), x)

    def needs_byte_swap(self):
        try:
            self.get_swap_to_host_func_name()
            return True
        except:
            pass
        return False


class CEnum(Enum):
    def get_c_name(self):
        return "vapi_enum_%s" % self.name

    def get_c_def(self):
        return "typedef enum {\n%s\n} %s;" % (
            "\n".join(["  %s = %s," % (i, j) for i, j in self.value_pairs]),
            self.get_c_name()
        )

    def needs_byte_swap(self):
        return self.type.needs_byte_swap()

    def get_swap_to_be_code(self, struct, var):
        return self.type.get_swap_to_be_code(struct, var, self.get_c_name())

    def get_swap_to_host_code(self, struct, var):
        return self.type.get_swap_to_host_code(struct, var, self.get_c_name())


class CUnion(Union):
    def get_c_name(self):
        return "vapi_union_%s" % self.name

    def get_c_def(self):
        return "typedef union {\n%s\n} %s;" % (
            "\n".join(["  %s %s;" % (i.get_c_name(), j)
                       for i, j in self.type_pairs]),
            self.get_c_name()
        )

    def needs_byte_swap(self):
        return False


class CStructType (StructType, CStruct):
    def get_c_name(self):
        return "vapi_type_%s" % self.name

    def get_swap_to_be_func_name(self):
        return "%s_hton" % self.get_c_name()

    def get_swap_to_host_func_name(self):
        return "%s_ntoh" % self.get_c_name()

    def get_swap_to_be_func_decl(self):
        return "void %s(%s *msg)" % (
            self.get_swap_to_be_func_name(), self.get_c_name())

    def get_swap_to_be_func_def(self):
        return "%s\n{\n%s\n}" % (
            self.get_swap_to_be_func_decl(),
            "\n".join([
                "  %s" % p.get_swap_to_be_code("msg->", "%s" % p.name)
                for p in self.fields if p.needs_byte_swap()]),
        )

    def get_swap_to_host_func_decl(self):
        return "void %s(%s *msg)" % (
            self.get_swap_to_host_func_name(), self.get_c_name())

    def get_swap_to_host_func_def(self):
        return "%s\n{\n%s\n}" % (
            self.get_swap_to_host_func_decl(),
            "\n".join([
                "  %s" % p.get_swap_to_host_code("msg->", "%s" % p.name)
                for p in self.fields if p.needs_byte_swap()]),
        )

    def get_swap_to_be_code(self, struct, var):
        return "%s(&%s%s);" % (self.get_swap_to_be_func_name(), struct, var)

    def get_swap_to_host_code(self, struct, var):
        return "%s(&%s%s);" % (self.get_swap_to_host_func_name(), struct, var)

    def needs_byte_swap(self):
        for f in self.fields:
            if f.needs_byte_swap():
                return True
        return False


class CMessage (Message):
    def __init__(self, logger, definition, json_parser):
        super(CMessage, self).__init__(logger, definition, json_parser)
        self.payload_members = [
            "  %s" % p.get_c_def()
            for p in self.fields
            if p.type != self.header
        ]

    def has_payload(self):
        return len(self.payload_members) > 0

    def get_msg_id_name(self):
        return "vapi_msg_id_%s" % self.name

    def get_c_name(self):
        return "vapi_msg_%s" % self.name

    def get_payload_struct_name(self):
        return "vapi_payload_%s" % self.name

    def get_alloc_func_vla_field_length_name(self, field):
        return "%s_array_size" % field.name

    def get_alloc_func_name(self):
        return "vapi_alloc_%s" % self.name

    def get_alloc_vla_param_names(self):
        return [self.get_alloc_func_vla_field_length_name(f)
                for f in self.fields
                if f.nelem_field is not None]

    def get_alloc_func_decl(self):
        return "%s* %s(struct vapi_ctx_s *ctx%s)" % (
            self.get_c_name(),
            self.get_alloc_func_name(),
            "".join([", size_t %s" % n for n in
                     self.get_alloc_vla_param_names()]))

    def get_alloc_func_def(self):
        extra = []
        if self.header.has_field('client_index'):
            extra.append(
                "  msg->header.client_index = vapi_get_client_index(ctx);")
        if self.header.has_field('context'):
            extra.append("  msg->header.context = 0;")
        return "\n".join([
            "%s" % self.get_alloc_func_decl(),
            "{",
            "  %s *msg = NULL;" % self.get_c_name(),
            "  const size_t size = sizeof(%s)%s;" % (
                self.get_c_name(),
                "".join([
                    " + sizeof(msg->payload.%s[0]) * %s" % (
                        f.name,
                        self.get_alloc_func_vla_field_length_name(f))
                    for f in self.fields
                    if f.nelem_field is not None
                ])),
            "  /* cast here required to play nicely with C++ world ... */",
            "  msg = (%s*)vapi_msg_alloc(ctx, size);" % self.get_c_name(),
            "  if (!msg) {",
            "    return NULL;",
            "  }",
        ] + extra + [
            "  msg->header._vl_msg_id = vapi_lookup_vl_msg_id(ctx, %s);" %
            self.get_msg_id_name(),
            "\n".join(["  msg->payload.%s = %s;" % (
                f.nelem_field.name,
                self.get_alloc_func_vla_field_length_name(f))
                for f in self.fields
                if f.nelem_field is not None]),
            "  return msg;",
            "}"])

    def get_calc_msg_size_func_name(self):
        return "vapi_calc_%s_msg_size" % self.name

    def get_calc_msg_size_func_decl(self):
        return "uword %s(%s *msg)" % (
            self.get_calc_msg_size_func_name(),
            self.get_c_name())

    def get_calc_msg_size_func_def(self):
        return "\n".join([
            "%s" % self.get_calc_msg_size_func_decl(),
            "{",
            "  return sizeof(*msg)%s;" %
            "".join(["+ msg->payload.%s * sizeof(msg->payload.%s[0])" % (
                    f.nelem_field.name,
                    f.name)
                for f in self.fields
                if f.nelem_field is not None
            ]),
            "}",
        ])

    def get_c_def(self):
        if self.has_payload():
            return "\n".join([
                "typedef struct __attribute__ ((__packed__)) {",
                "%s; " %
                ";\n".join(self.payload_members),
                "} %s;" % self.get_payload_struct_name(),
                "",
                "typedef struct __attribute__ ((__packed__)) {",
                ("  %s %s;" % (self.header.get_c_name(),
                               self.fields[0].name)
                    if self.header is not None else ""),
                "  %s payload;" % self.get_payload_struct_name(),
                "} %s;" % self.get_c_name(), ])
        else:
            return "\n".join([
                "typedef struct __attribute__ ((__packed__)) {",
                ("  %s %s;" % (self.header.get_c_name(),
                               self.fields[0].name)
                    if self.header is not None else ""),
                "} %s;" % self.get_c_name(), ])

    def get_swap_payload_to_host_func_name(self):
        return "%s_payload_ntoh" % self.get_c_name()

    def get_swap_payload_to_be_func_name(self):
        return "%s_payload_hton" % self.get_c_name()

    def get_swap_payload_to_host_func_decl(self):
        return "void %s(%s *payload)" % (
            self.get_swap_payload_to_host_func_name(),
            self.get_payload_struct_name())

    def get_swap_payload_to_be_func_decl(self):
        return "void %s(%s *payload)" % (
            self.get_swap_payload_to_be_func_name(),
            self.get_payload_struct_name())

    def get_swap_payload_to_be_func_def(self):
        return "%s\n{\n%s\n}" % (
            self.get_swap_payload_to_be_func_decl(),
            "\n".join([
                "  %s" % p.get_swap_to_be_code("payload->", "%s" % p.name)
                for p in self.fields
                if p.needs_byte_swap() and p.type != self.header]),
        )

    def get_swap_payload_to_host_func_def(self):
        return "%s\n{\n%s\n}" % (
            self.get_swap_payload_to_host_func_decl(),
            "\n".join([
                "  %s" % p.get_swap_to_host_code("payload->", "%s" % p.name)
                for p in self.fields
                if p.needs_byte_swap() and p.type != self.header]),
        )

    def get_swap_to_host_func_name(self):
        return "%s_ntoh" % self.get_c_name()

    def get_swap_to_be_func_name(self):
        return "%s_hton" % self.get_c_name()

    def get_swap_to_host_func_decl(self):
        return "void %s(%s *msg)" % (
            self.get_swap_to_host_func_name(), self.get_c_name())

    def get_swap_to_be_func_decl(self):
        return "void %s(%s *msg)" % (
            self.get_swap_to_be_func_name(), self.get_c_name())

    def get_swap_to_be_func_def(self):
        return "\n".join([
            "%s" % self.get_swap_to_be_func_decl(),
            "{",
            ("  VAPI_DBG(\"Swapping `%s'@%%p to big endian\", msg);" %
                self.get_c_name()),
            "  %s(&msg->header);" % self.header.get_swap_to_be_func_name()
            if self.header is not None else "",
            "  %s(&msg->payload);" % self.get_swap_payload_to_be_func_name()
            if self.has_payload() else "",
            "}",
        ])

    def get_swap_to_host_func_def(self):
        return "\n".join([
            "%s" % self.get_swap_to_host_func_decl(),
            "{",
            ("  VAPI_DBG(\"Swapping `%s'@%%p to host byte order\", msg);" %
                self.get_c_name()),
            "  %s(&msg->header);" % self.header.get_swap_to_host_func_name()
            if self.header is not None else "",
            "  %s(&msg->payload);" % self.get_swap_payload_to_host_func_name()
            if self.has_payload() else "",
            "}",
        ])

    def get_op_func_name(self):
        return "vapi_%s" % self.name

    def get_op_func_decl(self):
        if self.reply.has_payload():
            return "vapi_error_e %s(%s)" % (
                self.get_op_func_name(),
                ",\n  ".join([
                    'struct vapi_ctx_s *ctx',
                    '%s *msg' % self.get_c_name(),
                    'vapi_error_e (*callback)(struct vapi_ctx_s *ctx',
                    '                         void *callback_ctx',
                    '                         vapi_error_e rv',
                    '                         bool is_last',
                    '                         %s *reply)' %
                    self.reply.get_payload_struct_name(),
                    'void *callback_ctx',
                ])
            )
        else:
            return "vapi_error_e %s(%s)" % (
                self.get_op_func_name(),
                ",\n  ".join([
                    'struct vapi_ctx_s *ctx',
                    '%s *msg' % self.get_c_name(),
                    'vapi_error_e (*callback)(struct vapi_ctx_s *ctx',
                    '                         void *callback_ctx',
                    '                         vapi_error_e rv',
                    '                         bool is_last)',
                    'void *callback_ctx',
                ])
            )

    def get_op_func_def(self):
        return "\n".join([
            "%s" % self.get_op_func_decl(),
            "{",
            "  if (!msg || !callback) {",
            "    return VAPI_EINVAL;",
            "  }",
            "  if (vapi_is_nonblocking(ctx) && vapi_requests_full(ctx)) {",
            "    return VAPI_EAGAIN;",
            "  }",
            "  vapi_error_e rv;",
            "  if (VAPI_OK != (rv = vapi_producer_lock (ctx))) {",
            "    return rv;",
            "  }",
            "  u32 req_context = vapi_gen_req_context(ctx);",
            "  msg->header.context = req_context;",
            "  %s(msg);" % self.get_swap_to_be_func_name(),
            ("  if (VAPI_OK == (rv = vapi_send_with_control_ping "
                "(ctx, msg, req_context))) {"
                if self.reply_is_stream else
                "  if (VAPI_OK == (rv = vapi_send (ctx, msg))) {"
             ),
            ("    vapi_store_request(ctx, req_context, %s, "
             "(vapi_cb_t)callback, callback_ctx);" %
             ("true" if self.reply_is_stream else "false")),
            "    if (VAPI_OK != vapi_producer_unlock (ctx)) {",
            "      abort (); /* this really shouldn't happen */",
            "    }",
            "    if (vapi_is_nonblocking(ctx)) {",
            "      rv = VAPI_OK;",
            "    } else {",
            "      rv = vapi_dispatch(ctx);",
            "    }",
            "  } else {",
            "    %s(msg);" % self.get_swap_to_host_func_name(),
            "    if (VAPI_OK != vapi_producer_unlock (ctx)) {",
            "      abort (); /* this really shouldn't happen */",
            "    }",
            "  }",
            "  return rv;",
            "}",
            "",
        ])

    def get_event_cb_func_decl(self):
        if not self.is_reply and not self.is_event:
            raise Exception(
                "Cannot register event callback for non-reply message")
        if self.has_payload():
            return "\n".join([
                "void vapi_set_%s_event_cb (" %
                self.get_c_name(),
                "  struct vapi_ctx_s *ctx, ",
                ("  vapi_error_e (*callback)(struct vapi_ctx_s *ctx, "
                 "void *callback_ctx, %s *payload)," %
                 self.get_payload_struct_name()),
                "  void *callback_ctx)",
            ])
        else:
            return "\n".join([
                "void vapi_set_%s_event_cb (" %
                self.get_c_name(),
                "  struct vapi_ctx_s *ctx, ",
                "  vapi_error_e (*callback)(struct vapi_ctx_s *ctx, "
                "void *callback_ctx),",
                "  void *callback_ctx)",
            ])

    def get_event_cb_func_def(self):
        if not self.is_reply and not self.is_event:
            raise Exception(
                "Cannot register event callback for non-reply function")
        return "\n".join([
            "%s" % self.get_event_cb_func_decl(),
            "{",
            ("  vapi_set_event_cb(ctx, %s, (vapi_event_cb)callback, "
             "callback_ctx);" %
             self.get_msg_id_name()),
            "}"])

    def get_c_metadata_struct_name(self):
        return "__vapi_metadata_%s" % self.name

    def get_c_constructor(self):
        has_context = False
        if self.header is not None:
            has_context = self.header.has_field('context')
        return '\n'.join([
            'static void __attribute__((constructor)) __vapi_constructor_%s()'
            % self.name,
            '{',
            '  static const char name[] = "%s";' % self.name,
            '  static const char name_with_crc[] = "%s_%s";'
            % (self.name, self.crc[2:]),
            '  static vapi_message_desc_t %s = {' %
            self.get_c_metadata_struct_name(),
            '    name,',
            '    sizeof(name) - 1,',
            '    name_with_crc,',
            '    sizeof(name_with_crc) - 1,',
            '    true,' if has_context else '    false,',
            '    offsetof(%s, context),' % self.header.get_c_name()
            if has_context else '    0,',
            ('    offsetof(%s, payload),' % self.get_c_name())
            if self.has_payload() else '    VAPI_INVALID_MSG_ID,',
            '    sizeof(%s),' % self.get_c_name(),
            '    (generic_swap_fn_t)%s,' % self.get_swap_to_be_func_name(),
            '    (generic_swap_fn_t)%s,' % self.get_swap_to_host_func_name(),
            '    VAPI_INVALID_MSG_ID,',
            '  };',
            '',
            '  %s = vapi_register_msg(&%s);' %
            (self.get_msg_id_name(), self.get_c_metadata_struct_name()),
            '  VAPI_DBG("Assigned msg id %%d to %s", %s);' %
            (self.name, self.get_msg_id_name()),
            '}',
        ])


vapi_send_with_control_ping = """
static inline vapi_error_e
vapi_send_with_control_ping (vapi_ctx_t ctx, void *msg, u32 context)
{
  vapi_msg_control_ping *ping = vapi_alloc_control_ping (ctx);
  if (!ping)
    {
      return VAPI_ENOMEM;
    }
  ping->header.context = context;
  vapi_msg_control_ping_hton (ping);
  return vapi_send2 (ctx, msg, ping);
}
"""


def emit_definition(parser, json_file, emitted, o):
    if o in emitted:
        return
    if o.name in ("msg_header1_t", "msg_header2_t"):
        return
    if hasattr(o, "depends"):
        for x in o.depends:
            emit_definition(parser, json_file, emitted, x)
    if hasattr(o, "reply"):
        emit_definition(parser, json_file, emitted, o.reply)
    if hasattr(o, "get_c_def"):
        if (o not in parser.enums_by_json[json_file] and
                o not in parser.types_by_json[json_file] and
                o not in parser.unions_by_json[json_file] and
                o.name not in parser.messages_by_json[json_file]):
            return
        guard = "defined_%s" % o.get_c_name()
        print("#ifndef %s" % guard)
        print("#define %s" % guard)
        print("%s" % o.get_c_def())
        print("")
        function_attrs = "static inline "
        if o.name in parser.messages_by_json[json_file]:
            if o.has_payload():
                print("%s%s" % (function_attrs,
                                o.get_swap_payload_to_be_func_def()))
                print("")
                print("%s%s" % (function_attrs,
                                o.get_swap_payload_to_host_func_def()))
                print("")
            print("%s%s" % (function_attrs, o.get_swap_to_be_func_def()))
            print("")
            print("%s%s" % (function_attrs, o.get_swap_to_host_func_def()))
            print("")
            print("%s%s" % (function_attrs, o.get_calc_msg_size_func_def()))
            print("")
            if not o.is_reply and not o.is_event:
                print("%s%s" % (function_attrs, o.get_alloc_func_def()))
                print("")
                print("%s%s" % (function_attrs, o.get_op_func_def()))
                print("")
            print("%s" % o.get_c_constructor())
            print("")
            if o.is_reply or o.is_event:
                print("%s%s;" % (function_attrs, o.get_event_cb_func_def()))
                print("")
        elif hasattr(o, "get_swap_to_be_func_def"):
            print("%s%s" % (function_attrs, o.get_swap_to_be_func_def()))
            print("")
            print("%s%s" % (function_attrs, o.get_swap_to_host_func_def()))
            print("")
        print("#endif")
    emitted.append(o)


def gen_json_unified_header(parser, logger, j, io, name):
    d, f = os.path.split(j)
    logger.info("Generating header `%s'" % name)
    orig_stdout = sys.stdout
    sys.stdout = io
    include_guard = "__included_%s" % (
        j.replace(".", "_").replace("/", "_").replace("-", "_"))
    print("#ifndef %s" % include_guard)
    print("#define %s" % include_guard)
    print("")
    print("#include <stdlib.h>")
    print("#include <stddef.h>")
    print("#include <arpa/inet.h>")
    print("#include <vapi/vapi_internal.h>")
    print("#include <vapi/vapi.h>")
    print("#include <vapi/vapi_dbg.h>")
    print("")
    print("#ifdef __cplusplus")
    print("extern \"C\" {")
    print("#endif")
    if name == "vpe.api.vapi.h":
        print("")
        print("static inline vapi_error_e vapi_send_with_control_ping "
              "(vapi_ctx_t ctx, void * msg, u32 context);")
    else:
        print("#include <vapi/vpe.api.vapi.h>")
    print("")
    for m in parser.messages_by_json[j].values():
        print("extern vapi_msg_id_t %s;" % m.get_msg_id_name())
    print("")
    print("#define DEFINE_VAPI_MSG_IDS_%s\\" %
          f.replace(".", "_").replace("/", "_").replace("-", "_").upper())
    print("\\\n".join([
        "  vapi_msg_id_t %s;" % m.get_msg_id_name()
        for m in parser.messages_by_json[j].values()
    ]))
    print("")
    print("")
    emitted = []
    for e in parser.enums_by_json[j]:
        emit_definition(parser, j, emitted, e)
    for u in parser.unions_by_json[j]:
        emit_definition(parser, j, emitted, u)
    for t in parser.types_by_json[j]:
        emit_definition(parser, j, emitted, t)
    for m in parser.messages_by_json[j].values():
        emit_definition(parser, j, emitted, m)

    print("")

    if name == "vpe.api.vapi.h":
        print("%s" % vapi_send_with_control_ping)
        print("")

    print("#ifdef __cplusplus")
    print("}")
    print("#endif")
    print("")
    print("#endif")
    sys.stdout = orig_stdout


def json_to_c_header_name(json_name):
    if json_name.endswith(".json"):
        return "%s.vapi.h" % os.path.splitext(json_name)[0]
    raise Exception("Unexpected json name `%s'!" % json_name)


def gen_c_unified_headers(parser, logger, prefix, remove_path):
    if prefix == "" or prefix is None:
        prefix = ""
    else:
        prefix = "%s/" % prefix
    for j in parser.json_files:
        if remove_path:
            d, f = os.path.split(j)
        else:
            f = j
        with open('%s%s' % (prefix, json_to_c_header_name(f)), "w") as io:
            gen_json_unified_header(
                parser, logger, j, io, json_to_c_header_name(f))


if __name__ == '__main__':
    try:
        verbose = int(os.getenv("V", 0))
    except:
        verbose = 0

    if verbose >= 2:
        log_level = 10
    elif verbose == 1:
        log_level = 20
    else:
        log_level = 40

    logging.basicConfig(stream=sys.stdout, level=log_level)
    logger = logging.getLogger("VAPI C GEN")
    logger.setLevel(log_level)

    argparser = argparse.ArgumentParser(description="VPP C API generator")
    argparser.add_argument('files', metavar='api-file', action='append',
                           type=str, help='json api file'
                           '(may be specified multiple times)')
    argparser.add_argument('--prefix', action='store', default=None,
                           help='path prefix')
    argparser.add_argument('--remove-path', action='store_true',
                           help='remove path from filename')
    args = argparser.parse_args()

    jsonparser = JsonParser(logger, args.files,
                            simple_type_class=CSimpleType,
                            enum_class=CEnum,
                            union_class=CUnion,
                            struct_type_class=CStructType,
                            field_class=CField,
                            message_class=CMessage)

    # not using the model of having separate generated header and code files
    # with generated symbols present in shared library (per discussion with
    # Damjan), to avoid symbol version issues in .so
    # gen_c_headers_and_code(jsonparser, logger, args.prefix)

    gen_c_unified_headers(jsonparser, logger, args.prefix, args.remove_path)

    for e in jsonparser.exceptions:
        logger.warning(e)