From eblima at linux.vnet.ibm.com Mon Jan 2 11:38:05 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Mon, 02 Jan 2012 09:38:05 -0200 Subject: [Libvirt-cim] [PATCH 2/2] ComputerSystemIndication: Support libvirt domain events In-Reply-To: <4EFE1C86.3010305@linux.vnet.ibm.com> References: <1325181355-20808-1-git-send-email-eblima@linux.vnet.ibm.com> <1325181355-20808-3-git-send-email-eblima@linux.vnet.ibm.com> <4EFE1C86.3010305@linux.vnet.ibm.com> Message-ID: <4F01971D.9050404@linux.vnet.ibm.com> On 12/30/2011 06:18 PM, Chip Vincent wrote: > The code looks good but I'm seeing some strange failures on my system > with this patch applied. > > System details: > Red Hat Enterprise Linux Workstation release 6.2 (Santiago) > Linux oc4551028142.ibm.com 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 > 08:03:13 EST 2011 x86_64 x86_64 x86_64 GNU/Linux > > tog-pegasus-2.11.0-2.el6.x86_64 > libvirt-0.9.4-23.el6_2.1.x86_64 > > I need to dig a bit deeper, but here's what I've got so far. > > With CU_DEBUG enabled, here's the last few lines of the libvirt-cim.log: > std_indication.c(124): In raise > std_indication.c(140): Indication is > KVM_ResourceAllocationSettingDataCreatedIndication > std_indication.c(67): Indications disabled for this provider > std_invokemethod.c(301): Method `DefineSystem' returned 0 > > Back trace from core file: > 0 0x00007f28c7251c6a in > Pegasus::SCMOInstance::getCIMInstance(Pegasus::CIMInstance&) const () > from /usr/lib64/libpegcommon.so.1 > #1 0x00007f28c3bb753c in ?? () > from /usr/lib64/Pegasus/providerManagers/libCMPIProviderManager.so > #2 0x00007f28c3ba3e2d in ?? () > from /usr/lib64/Pegasus/providerManagers/libCMPIProviderManager.so > #3 0x00007f28c2f75c93 in _std_invokemethod () from > /usr/lib64/libcmpiutil.so.0 > #4 0x00007f28c3b80df2 in > Pegasus::CMPIProviderManager::handleInvokeMethodRequest(Pegasus::Message > const*) () > from /usr/lib64/Pegasus/providerManagers/libCMPIProviderManager.so > #5 0x00007f28c3b923db in > Pegasus::CMPIProviderManager::processMessage(Pegasus::Message*) () from > /usr/lib64/Pegasus/providerManagers/libCMPIProviderManager.so > #6 0x00007f28c8b4a1c6 in > Pegasus::BasicProviderManagerRouter::processMessage(Pegasus::Message*) > () from /usr/lib64/libpegpmrouter.so.1 > #7 0x00007f28c8f7e738 in ?? () > #8 0x00007f28c8f7f925 in ?? () > #9 0x00007f28c72f21c5 in Pegasus::ThreadPool::_loop(void*) () > from /usr/lib64/libpegcommon.so.1 > #10 0x00007f28c6da07f1 in start_thread () from /lib64/libpthread.so.0 > #11 0x00007f28c610670d in clone () from /lib64/libc.so.6 > > Just to be safe, I removed this patch and re-ran cimtest and *did not* > get the crashes. I do see some failures, but they seem relatively minor. > I then re-applied the patch and could reproduce the failures. > Ouch, my bad. I should have make sure the other test cases were not impacted by this patch. > The failures appear in different cimtests on most runs. Here's one > example: "ComputerSystem - 05_activate_defined_start.py: FAIL > ERROR - Got CIM error CIM_ERR_FAILED: Lost connection with > cimprovagt "libvirt-cim". with return code 1". Once you get the first > failure, it appears the follow-on failures are side effects of some form > of corruption in libvirt-cim or libvirt. For example: "ERROR - Got > CIM error CIM_ERR_FAILED: The byte sequence starting at index 0 is not > valid UTF-8 encoding: 0x89 0x04 0x24 0x48 0x83 0xC4 0x28 0xC3 0x66 0x0F > 0x1F with return code 1" > > Libvirt is often left in an odd state once I get a failure. I've seen > test VMs left over that cannot be deleted with Virt Mgr, and once I was > unable to connect to libvirt at all, which required a service restart. > > I'll post more once I have a chance to experiment more. While I was developing this feature I was having serious problems, aleatory crashes most probably due to race conditions. This seems to be the problem in this case. -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Mon Jan 2 11:39:58 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Mon, 02 Jan 2012 09:39:58 -0200 Subject: [Libvirt-cim] [PATCH 2/2] ComputerSystemIndication: Support libvirt domain events In-Reply-To: <4EFE56D0.4030002@linux.vnet.ibm.com> References: <1325181355-20808-1-git-send-email-eblima@linux.vnet.ibm.com> <1325181355-20808-3-git-send-email-eblima@linux.vnet.ibm.com> <4EFE56D0.4030002@linux.vnet.ibm.com> Message-ID: <4F01978E.7070002@linux.vnet.ibm.com> On 12/30/2011 10:26 PM, Chip Vincent wrote: > It appears there is a bug causing a crash somewhere between > virConnectDomainEventRegisterAny() and here. Disabling this > section of code avoids the crashes I mentioned > (https://www.redhat.com/archives/libvirt-cim/2011-December/msg00086.html). > Of course, that effectively disables much more code... baby steps. > NOTE: I have yet to get a meaningful backtrace, which suggests some > memory or stack corruption and the functions in the backtrace are likely a > victim. I'm looking at the list handling code now. Threads, threads... :/ >> - fail: >> - if (failure) { >> - wait_for_event(FAIL_WAIT_TIME); >> - } else { >> - free(prev_xml); >> - prev_xml = cur_xml; >> - prev_count = cur_count; >> >> - wait_for_event(WAIT_TIME); >> + CU_DEBUG("Entering CSI event loop (%s)", prefix); >> + while (thread->active_filters> 0) { >> + if (virEventRunDefaultImpl()< 0) { >> + virErrorPtr err = virGetLastError(); >> + CU_DEBUG("Failed to run event loop: %s\n", >> + err&& err->message ? err->message : "Unknown >> error"); >> } >> } > I believe you need to call CBDetachThread() here so that CMPI can clean-up > objects created during the thread's lifecycle. Otherwise, it will appear > like > a leak since the CIMOM and Indication Providers run indefinitely. > Thanks for the insight. I felt that this call to CBDetachThread was missing at first, but the original implementation did not include it so I left it behind. -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Mon Jan 2 11:58:18 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Mon, 02 Jan 2012 09:58:18 -0200 Subject: [Libvirt-cim] [PATCH 2/2] ComputerSystemIndication: Support libvirt domain events In-Reply-To: <4EFF577C.1050901@linux.vnet.ibm.com> References: <1325181355-20808-1-git-send-email-eblima@linux.vnet.ibm.com> <1325181355-20808-3-git-send-email-eblima@linux.vnet.ibm.com> <4EFF577C.1050901@linux.vnet.ibm.com> Message-ID: <4F019BDA.60206@linux.vnet.ibm.com> On 12/31/2011 04:42 PM, Chip Vincent wrote: > Follow up from my previous comments... > > I think the problem is related to the use of > virEventRegisterDefaultImpl() in libvirt_cim_init(), which is called by > all providers, not just indication providers. Given the number of times > we call that function, perhaps we're overloading libvirt and/or > triggering an underlying bug. When I either comment out that function, I > see no crashes. I then moved it to be called once in > ComputerSystemIndication->ActivateFilter() (via a static init variable), > and I was able to avoid the crashes. Unfortunately, I'm not able to > verify the domain events function via cimtest. FWIW, I see the same > message w/o the patch so perhaps I need to do something else to make it > work. > This sounds weird, if you notice the virEventRegisterDefaultImpl() call is protected both by a static variable in libxkutil/misc_util.c and a mutex lock. I could also protect the call with a static variable to avoid calling it everytime. > ComputerSystemIndication - 01_created_indication.py: FAIL > ERROR - Waited too long for define indication > ERROR - Exception: Poll for indication Failed > ERROR - Waited too long for start indication > ERROR - Exception: Poll for indication Failed > ERROR - Waited too long for destroy indication > ERROR - Exception: Poll for indication Failed > > Here's a quick peek at the changes I made for reference: > > Remove virEventRegisterDefaultImpl() from init functon > > diff --git a/libxkutil/misc_util.c b/libxkutil/misc_util.c > index 556fe1f..61893c3 100644 > --- a/libxkutil/misc_util.c > +++ b/libxkutil/misc_util.c > @@ -607,8 +607,6 @@ bool libvirt_cim_init(void) > ret = virInitialize(); > if (ret == 0) > libvirt_initialized = 1; > - > - virEventRegisterDefaultImpl(); > } > pthread_mutex_unlock(&libvirt_mutex); > } > > Initialize entire csi_thread_data_t structures. Not sure if a single > '{0}' sets *all* members to 0 and > I wanted to be sure the active_filters member was set to 0 before > incrementing/decrementing. Yes, it does initialize everything. In fact, it is actually unnecessary to initialize any of the global static variables, as it is defined in the C language specification that they should be initialized automatically with zero (if not explicitly initialized). > Also added one time call to virEventRegisterDefaultImpl() to > ActiveFilter(). > > diff --git a/src/Virt_ComputerSystemIndication.c > b/src/Virt_ComputerSystemIndication.c > index 0df73f3..1ea8520 100644 > --- a/src/Virt_ComputerSystemIndication.c > +++ b/src/Virt_ComputerSystemIndication.c > @@ -80,7 +80,10 @@ struct _csi_thread_data_t { > static const CMPIBroker *_BROKER; > static pthread_mutex_t lifecycle_mutex = PTHREAD_MUTEX_INITIALIZER; > static bool lifecycle_enabled = false; > -static csi_thread_data_t csi_thread_data[CSI_NUM_PLATFORMS] = {{0}, > {0}, {0}}; > +static csi_thread_data_t csi_thread_data[CSI_NUM_PLATFORMS] = > + {{0, 0, 0, 0, 0}, > + {0, 0, 0, 0, 0}, > + {0, 0, 0, 0, 0}}; > > /* > * Domain list manipulation > @@ -698,6 +703,13 @@ static CMPIStatus ActivateFilter(CMPIIndicationMI* mi, > bool error = false; > csi_thread_data_t *thread = NULL; > > + static int _init = 0; > + > + if(_init == 0) { > + _init = 1; > + virEventRegisterDefaultImpl(); > + } > + > CU_DEBUG("ActivateFilter for %s", CLASSNAME(op)); > > pthread_mutex_lock(&lifecycle_mutex); > > I will try this. Thanks -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Mon Jan 2 18:52:54 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Mon, 2 Jan 2012 16:52:54 -0200 Subject: [Libvirt-cim] [PATCHv2] ComputerSystemIndication: Support libvirt domain events Message-ID: <1325530374-31634-1-git-send-email-eblima@linux.vnet.ibm.com> From: Eduardo Lima (Etrunko) Port current implementation to use domain events implementation provided by libvirt. It requires libvirt version 0.9.0 or newer, when the virEventRegisterDefaultImpl and virEventRunDefaultImpl API's were introduced. Now that all events are generated by libvirt itself, we don't need to trigger them manually anymore. Thus, this patch also removes trigger and raise calls from VirtualSystemManagementService and ComputerSystem providers. Differences from v1: - Move call to virRegisterDefaultImpl() to the provider code with protection to ensure it is called only once. - Call CBDetachThread() before exiting the lifecycle thread. Signed-off-by: Eduardo Lima (Etrunko) --- acinclude.m4 | 2 +- libvirt-cim.spec.in | 4 +- src/Virt_ComputerSystem.c | 51 +-- src/Virt_ComputerSystemIndication.c | 766 ++++++++++++++--------------- src/Virt_ComputerSystemIndication.h | 5 - src/Virt_VirtualSystemManagementService.c | 30 +- 6 files changed, 378 insertions(+), 480 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index e313891..e0f76b6 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -243,7 +243,7 @@ AC_DEFUN([CHECK_LIBCU], AC_DEFUN([CHECK_LIBVIRT], [ - PKG_CHECK_MODULES([LIBVIRT], [libvirt >= 0.3.2]) + PKG_CHECK_MODULES([LIBVIRT], [libvirt >= 0.9.0]) AC_SUBST([LIBVIRT_CFLAGS]) AC_SUBST([LIBVIRT_LIBS]) CPPFLAGS="$CPPFLAGS $LIBVIRT_CFLAGS" diff --git a/libvirt-cim.spec.in b/libvirt-cim.spec.in index 5b7267b..f3289db 100644 --- a/libvirt-cim.spec.in +++ b/libvirt-cim.spec.in @@ -10,12 +10,12 @@ Source: libvirt-cim-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root URL: http://libvirt.org/CIM/ Requires: libxml2 >= 2.6.0 -Requires: libvirt >= 0.6.3 +Requires: libvirt >= 0.9.0 Requires: unzip Requires: tog-pegasus BuildRequires: libcmpiutil >= 0.5.4 BuildRequires: tog-pegasus-devel -BuildRequires: libvirt-devel >= 0.6.3 +BuildRequires: libvirt-devel >= 0.9.0 # In RHEL5 uuid-devel is provided by e2fsprogs %if 0%{?el5} diff --git a/src/Virt_ComputerSystem.c b/src/Virt_ComputerSystem.c index 098b07a..582253a 100644 --- a/src/Virt_ComputerSystem.c +++ b/src/Virt_ComputerSystem.c @@ -492,6 +492,7 @@ static CMPIStatus set_properties(const CMPIBroker *broker, } if (!set_name_from_dom(dom, instance)) { + CU_DEBUG("Unable to get domain name"); virt_set_status(broker, &s, CMPI_RC_ERR_FAILED, virDomainGetConnect(dom), @@ -500,6 +501,7 @@ static CMPIStatus set_properties(const CMPIBroker *broker, } if (!set_uuid_from_dom(dom, instance, &uuid)) { + CU_DEBUG("Unable to get domain uuid"); virt_set_status(broker, &s, CMPI_RC_ERR_FAILED, virDomainGetConnect(dom), @@ -514,6 +516,7 @@ static CMPIStatus set_properties(const CMPIBroker *broker, } if (!set_state_from_dom(broker, dom, instance)) { + CU_DEBUG("Unable to get domain info"); virt_set_status(broker, &s, CMPI_RC_ERR_FAILED, virDomainGetConnect(dom), @@ -660,6 +663,7 @@ CMPIStatus get_domain_by_name(const CMPIBroker *broker, conn = connect_by_classname(broker, CLASSNAME(reference), &s); if (conn == NULL) { + CU_DEBUG("No such instance"); cu_statusf(broker, &s, CMPI_RC_ERR_NOT_FOUND, "No such instance."); @@ -668,6 +672,7 @@ CMPIStatus get_domain_by_name(const CMPIBroker *broker, dom = virDomainLookupByName(conn, name); if (dom == NULL) { + CU_DEBUG("Domain '%s' does not exist", name); virt_set_status(broker, &s, CMPI_RC_ERR_NOT_FOUND, conn, @@ -681,8 +686,10 @@ CMPIStatus get_domain_by_name(const CMPIBroker *broker, conn, dom, &inst); - if (s.rc != CMPI_RC_OK) + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("Unable to retrieve instance from domain"); goto out; + } *_inst = inst; @@ -766,39 +773,6 @@ DEFAULT_DI(); DEFAULT_EQ(); DEFAULT_INST_CLEANUP(); -static bool trigger_mod_indication(const CMPIContext *context, - CMPIInstance *prev_inst, - const CMPIObjectPath *ref) -{ - CMPIStatus s = {CMPI_RC_OK, NULL}; - const char *ind_name = "ComputerSystemModifiedIndication"; - CMPIInstance *ind = NULL; - char *type = NULL; - - CU_DEBUG("Preparing ComputerSystem indication"); - - ind = get_typed_instance(_BROKER, - CLASSNAME(ref), - ind_name, - NAMESPACE(ref)); - if (ind == NULL) { - CU_DEBUG("Failed to create ind '%s'", ind_name); - goto out; - } - - CU_DEBUG("Setting PreviousInstance"); - CMSetProperty(ind, "PreviousInstance", - (CMPIValue *)&prev_inst, CMPI_instance); - - type = get_typed_class(CLASSNAME(ref), ind_name); - - s = stdi_raise_indication(_BROKER, context, type, NAMESPACE(ref), ind); - - out: - free(type); - return s.rc == CMPI_RC_OK; -} - static int xen_scheduler_params(struct infostore_ctx *ctx, virSchedParameter **params) { @@ -1253,7 +1227,6 @@ static CMPIStatus state_change(CMPIMethodMI *self, int ret; const char *name = NULL; uint32_t rc = 1; - bool ind_rc; ret = cu_get_u16_arg(argsin, "RequestedState", &state); if (ret != CMPI_RC_OK) { @@ -1282,13 +1255,9 @@ static CMPIStatus state_change(CMPIMethodMI *self, s = __state_change(name, state, reference); - if (s.rc == CMPI_RC_OK) { - ind_rc= trigger_mod_indication(context, prev_inst, reference); - if (!ind_rc) - CU_DEBUG("Unable to trigger indication"); - + if (s.rc == CMPI_RC_OK) rc = 0; - } + out: CMReturnData(results, &rc, CMPI_uint32); diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c index a00444d..eb1a71c 100644 --- a/src/Virt_ComputerSystemIndication.c +++ b/src/Virt_ComputerSystemIndication.c @@ -25,13 +25,13 @@ #include #include #include -#include #include #include #include #include +#include #include #include @@ -44,158 +44,187 @@ #include "Virt_ComputerSystemIndication.h" #include "Virt_HostSystem.h" -static const CMPIBroker *_BROKER; #define CSI_NUM_PLATFORMS 3 -enum CSI_PLATFORMS {CSI_XEN, - CSI_KVM, - CSI_LXC, +enum CSI_PLATFORMS { + CSI_XEN, + CSI_KVM, + CSI_LXC, }; -static CMPI_THREAD_TYPE thread_id[CSI_NUM_PLATFORMS]; -static int active_filters[CSI_NUM_PLATFORMS]; - -enum CS_EVENTS {CS_CREATED, - CS_DELETED, - CS_MODIFIED, +#define CS_NUM_EVENTS 3 +enum CS_EVENTS { + CS_CREATED, + CS_DELETED, + CS_MODIFIED, }; -static pthread_cond_t lifecycle_cond = PTHREAD_COND_INITIALIZER; -static pthread_mutex_t lifecycle_mutex = PTHREAD_MUTEX_INITIALIZER; -static bool lifecycle_enabled = 0; - -#define WAIT_TIME 60 -#define FAIL_WAIT_TIME 2 - -struct dom_xml { +typedef struct _csi_dom_xml_t csi_dom_xml_t; +struct _csi_dom_xml_t { char uuid[VIR_UUID_STRING_BUFLEN]; + char *name; char *xml; - enum {DOM_OFFLINE, - DOM_ONLINE, - DOM_PAUSED, - DOM_CRASHED, - DOM_GONE, - } state; + csi_dom_xml_t *next; + csi_dom_xml_t *prev; +}; + +typedef struct _csi_thread_data_t csi_thread_data_t; +struct _csi_thread_data_t { + CMPI_THREAD_TYPE id; + int active_filters; + int dom_count; + csi_dom_xml_t *dom_list; + struct ind_args *args; }; -static void free_dom_xml (struct dom_xml dom) +static const CMPIBroker *_BROKER; +static pthread_mutex_t lifecycle_mutex = PTHREAD_MUTEX_INITIALIZER; +static bool lifecycle_enabled = false; +static csi_thread_data_t csi_thread_data[CSI_NUM_PLATFORMS] = {{0}, {0}, {0}}; + +/* + * Domain list manipulation + */ +static void csi_dom_xml_free(csi_dom_xml_t *dom) { - free(dom.xml); + free(dom->xml); + free(dom->name); + free(dom); } -static char *sys_name_from_xml(char *xml) +static int csi_dom_xml_set(csi_dom_xml_t *dom, virDomainPtr dom_ptr, CMPIStatus *s) { - char *tmp = NULL; - char *name = NULL; - int rc; + const char *name; - tmp = strstr(xml, ""); - if (tmp == NULL) - goto out; + name = virDomainGetName(dom_ptr); + if (name == NULL) { + cu_statusf(_BROKER, s, + CMPI_RC_ERR_FAILED, + "Failed to get domain name"); + return -1; + } - rc = sscanf(tmp, "%a[^<]s", &name); - if (rc != 1) - name = NULL; + dom->name = strdup(name); + + /* xml */ + dom->xml = virDomainGetXMLDesc(dom_ptr, VIR_DOMAIN_XML_SECURE); + if (dom->xml == NULL) { + cu_statusf(_BROKER, s, + CMPI_RC_ERR_FAILED, + "Failed to get xml desc"); + return -1; + } - out: - return name; + return 0; } -static int dom_state(virDomainPtr dom) +static csi_dom_xml_t *csi_dom_xml_new(virDomainPtr dom_ptr, CMPIStatus *s) { - virDomainInfo info; - int ret; + int rc; + csi_dom_xml_t *dom; - ret = virDomainGetInfo(dom, &info); - if (ret != 0) - return DOM_GONE; + dom = calloc(1, sizeof(*dom)); + if (dom == NULL) + return NULL; - switch (info.state) { - case VIR_DOMAIN_NOSTATE: - case VIR_DOMAIN_RUNNING: - case VIR_DOMAIN_BLOCKED: - return DOM_ONLINE; + /* uuid */ + rc = virDomainGetUUIDString(dom_ptr, dom->uuid); + if (rc == -1) { + cu_statusf(_BROKER, s, + CMPI_RC_ERR_FAILED, + "Failed to get domain UUID"); + goto error; + } - case VIR_DOMAIN_PAUSED: - return DOM_PAUSED; + if (csi_dom_xml_set(dom, dom_ptr, s) == -1) + goto error; - case VIR_DOMAIN_SHUTOFF: - return DOM_OFFLINE; + return dom; - case VIR_DOMAIN_CRASHED: - return DOM_CRASHED; + error: + csi_dom_xml_free(dom); + return NULL; +} - default: - return DOM_GONE; - }; +static void csi_thread_dom_list_append(csi_thread_data_t *thread, + csi_dom_xml_t *dom) +{ + /* empty list */ + if (thread->dom_list == NULL) { + dom->next = dom->prev = dom; + thread->dom_list = dom; + goto end; + } + + dom->next = thread->dom_list; + dom->prev = thread->dom_list->prev; + + thread->dom_list->prev->next = dom; + thread->dom_list->prev = dom; + + end: + thread->dom_count += 1; } -static CMPIStatus doms_to_xml(struct dom_xml **dom_xml_list, - virDomainPtr *dom_ptr_list, - int dom_ptr_count) +static csi_dom_xml_t *csi_thread_dom_list_find(csi_thread_data_t *thread, + const char *uuid) { - int i; - int rc; - CMPIStatus s = {CMPI_RC_OK, NULL}; + csi_dom_xml_t *dom; - *dom_xml_list = calloc(dom_ptr_count, sizeof(struct dom_xml)); - for (i = 0; i < dom_ptr_count; i++) { - rc = virDomainGetUUIDString(dom_ptr_list[i], - (*dom_xml_list)[i].uuid); - if (rc == -1) { - cu_statusf(_BROKER, &s, - CMPI_RC_ERR_FAILED, - "Failed to get UUID"); - /* If any domain fails, we fail. */ - break; - } + if (thread->dom_list == NULL) + return NULL; - (*dom_xml_list)[i].xml = virDomainGetXMLDesc(dom_ptr_list[i], - VIR_DOMAIN_XML_SECURE); - if ((*dom_xml_list)[i].xml == NULL) { - cu_statusf(_BROKER, &s, - CMPI_RC_ERR_FAILED, - "Failed to get xml desc"); - break; - } + dom = thread->dom_list; + + do { + if (STREQ(dom->uuid, uuid)) + return dom; - (*dom_xml_list)[i].state = dom_state(dom_ptr_list[i]); + dom = dom->next; + } while (dom != thread->dom_list); + + return NULL; +} + +static void csi_thread_dom_list_remove(csi_thread_data_t *thread, + csi_dom_xml_t *dom) +{ + if (dom->next == dom) { /* Only one node */ + thread->dom_list = NULL; + } else { + if (thread->dom_list == dom) /* First node */ + thread->dom_list = dom->next; + + dom->prev->next = dom->next; + dom->next->prev = dom->prev; } - - return s; + + thread->dom_count -= 1; + + csi_dom_xml_free(dom); } -static bool dom_changed(struct dom_xml prev_dom, - struct dom_xml *cur_xml, - int cur_count) +static void csi_thread_dom_list_free(csi_thread_data_t *thread) { - int i; - bool ret = false; - - for (i = 0; i < cur_count; i++) { - if (strcmp(cur_xml[i].uuid, prev_dom.uuid) != 0) - continue; - - if (strcmp(cur_xml[i].xml, prev_dom.xml) != 0) { - CU_DEBUG("Domain config changed"); - ret = true; - } + while(thread->dom_list != NULL) + csi_thread_dom_list_remove(thread, thread->dom_list); +} - if (prev_dom.state != cur_xml[i].state) { - CU_DEBUG("Domain state changed"); - ret = true; - } +static void csi_free_thread_data(void *data) +{ + csi_thread_data_t *thread = (csi_thread_data_t *) data; - break; - } - - return ret; + if (data == NULL) + return; + + csi_thread_dom_list_free(thread); + stdi_free_ind_args(&thread->args); } void set_source_inst_props(const CMPIBroker *broker, - const CMPIContext *context, - const CMPIObjectPath *ref, - CMPIInstance *ind) + const CMPIContext *context, + const CMPIObjectPath *ref, + CMPIInstance *ind) { const char *host; const char *hostccn; @@ -225,7 +254,7 @@ static bool _do_indication(const CMPIBroker *broker, CMPIInstance *prev_inst, CMPIInstance *affected_inst, int ind_type, - char *prefix, + const char *prefix, struct ind_args *args) { const char *ind_type_name = NULL; @@ -254,10 +283,10 @@ static bool _do_indication(const CMPIBroker *broker, ind_type_name, args->ns); - /* Generally report errors and hope to continue, since we have no one + /* Generally report errors and hope to continue, since we have no one to actually return status to. */ if (ind == NULL) { - CU_DEBUG("Failed to create ind, type '%s:%s_%s'", + CU_DEBUG("Failed to create ind, type '%s:%s_%s'", args->ns, prefix, ind_type_name); @@ -279,14 +308,15 @@ static bool _do_indication(const CMPIBroker *broker, CU_DEBUG("problem getting affected_op: '%s'", s.msg); goto out; } + CMSetNameSpace(affected_op, args->ns); uuid = CMGetProperty(affected_inst, "UUID", &s); - CMSetProperty(ind, "IndicationIdentifier", + CMSetProperty(ind, "IndicationIdentifier", (CMPIValue *)&(uuid.value), CMPI_string); timestamp = CMNewDateTime(broker, &s); - CMSetProperty(ind, "IndicationTime", + CMSetProperty(ind, "IndicationTime", (CMPIValue *)×tamp, CMPI_dateTime); if (ind_type == CS_MODIFIED) { @@ -313,34 +343,6 @@ static bool _do_indication(const CMPIBroker *broker, return ret; } -static bool wait_for_event(int wait_time) -{ - struct timespec timeout; - int ret; - - - clock_gettime(CLOCK_REALTIME, &timeout); - timeout.tv_sec += wait_time; - - ret = pthread_cond_timedwait(&lifecycle_cond, - &lifecycle_mutex, - &timeout); - - return true; -} - -static bool dom_in_list(char *uuid, int count, struct dom_xml *list) -{ - int i; - - for (i = 0; i < count; i++) { - if (STREQ(uuid, list[i].uuid)) - return true; - } - - return false; -} - static bool set_instance_state(CMPIInstance *instance) { CMPIStatus s = {CMPI_RC_OK, NULL}; @@ -356,7 +358,7 @@ static bool set_instance_state(CMPIInstance *instance) cim_state_other = CMNewString(_BROKER, "Guest destroyed", &s); CMSetProperty(instance, "EnabledState", (CMPIValue *)&cim_state, CMPI_uint16); - CMSetProperty(instance, "OtherEnabledState", + CMSetProperty(instance, "OtherEnabledState", (CMPIValue *)&cim_state_other, CMPI_string); health_state = CIM_HEALTH_UNKNOWN; @@ -382,13 +384,13 @@ static bool set_instance_state(CMPIInstance *instance) req_state = CIM_STATE_UNKNOWN; CMSetProperty(instance, "RequestedState", (CMPIValue *)&req_state, CMPI_uint16); - + return true; } -static bool create_deleted_guest_inst(char *xml, - char *namespace, - char *prefix, +static bool create_deleted_guest_inst(const char *xml, + const char *namespace, + const char *prefix, CMPIInstance **inst) { bool rc = false; @@ -402,18 +404,18 @@ static bool create_deleted_guest_inst(char *xml, goto out; } - s = instance_from_dominfo(_BROKER, - namespace, + s = instance_from_dominfo(_BROKER, + namespace, prefix, - dominfo, - inst); + dominfo, + inst); if (s.rc != CMPI_RC_OK) { CU_DEBUG("instance from domain info error: %s", s.msg); goto out; } rc = set_instance_state(*inst); - if (!rc) + if (!rc) CU_DEBUG("Error setting instance state"); out: @@ -422,14 +424,12 @@ static bool create_deleted_guest_inst(char *xml, return rc; } -static bool async_ind(CMPIContext *context, +static bool async_ind(struct ind_args *args, int ind_type, - struct dom_xml prev_dom, - char *prefix, - struct ind_args *args) + csi_dom_xml_t *dom, + const char *prefix) { bool rc = false; - char *name = NULL; char *cn = NULL; CMPIObjectPath *op; CMPIInstance *prev_inst; @@ -441,13 +441,6 @@ static bool async_ind(CMPIContext *context, return false; } - name = sys_name_from_xml(prev_dom.xml); - CU_DEBUG("Name for system: '%s'", name); - if (name == NULL) { - rc = false; - goto out; - } - cn = get_typed_class(prefix, "ComputerSystem"); op = CMNewObjectPath(_BROKER, args->ns, cn, &s); @@ -457,15 +450,32 @@ static bool async_ind(CMPIContext *context, } if (ind_type == CS_CREATED || ind_type == CS_MODIFIED) { - s = get_domain_by_name(_BROKER, op, name, &affected_inst); - if (s.rc != CMPI_RC_OK) { + s = get_domain_by_name(_BROKER, op, dom->name, &affected_inst); + + /* If domain is not found, we create the instance from the data + previously stored */ + if (s.rc == CMPI_RC_ERR_NOT_FOUND) { + rc = create_deleted_guest_inst(dom->xml, + args->ns, + prefix, + &affected_inst); + if (!rc) { + CU_DEBUG("Could not recreate guest instance"); + goto out; + } + + s.rc = CMPI_RC_OK; + } + + if (s.rc != CMPI_RC_OK) { CU_DEBUG("domain by name error"); goto out; } + } else if (ind_type == CS_DELETED) { - rc = create_deleted_guest_inst(prev_dom.xml, - args->ns, - prefix, + rc = create_deleted_guest_inst(dom->xml, + args->ns, + prefix, &affected_inst); if (!rc) { CU_DEBUG("Could not recreate guest instance"); @@ -476,52 +486,134 @@ static bool async_ind(CMPIContext *context, goto out; } - /* FIXME: We are unable to get the previous CS instance after it has + /* FIXME: We are unable to get the previous CS instance after it has been modified. Consider keeping track of the previous - state in the place we keep track of the requested state */ + state in the place we keep track of the requested state */ prev_inst = affected_inst; - CMSetProperty(affected_inst, "Name", - (CMPIValue *)name, CMPI_chars); + CMSetProperty(affected_inst, "Name", + (CMPIValue *) dom->name, CMPI_chars); CMSetProperty(affected_inst, "UUID", - (CMPIValue *)prev_dom.uuid, CMPI_chars); + (CMPIValue *) dom->uuid, CMPI_chars); - rc = _do_indication(_BROKER, context, prev_inst, affected_inst, + rc = _do_indication(_BROKER, args->context, prev_inst, affected_inst, ind_type, prefix, args); out: free(cn); - free(name); return rc; } -static int platform_from_class(const char *cn) +static int update_domain_list(virConnectPtr conn, csi_thread_data_t *thread) { - if (STARTS_WITH(cn, "Xen")) - return CSI_XEN; - else if (STARTS_WITH(cn, "KVM")) - return CSI_KVM; - else if (STARTS_WITH(cn, "LXC")) - return CSI_LXC; - else - return -1; + virDomainPtr *dom_ptr_list; + csi_dom_xml_t *dom; + CMPIStatus s = {CMPI_RC_OK, NULL}; + int i, count; + + csi_thread_dom_list_free(thread); + + count = get_domain_list(conn, &dom_ptr_list); + + for (i = 0; i < count; i++) { + dom = csi_dom_xml_new(dom_ptr_list[i], &s); + if (dom == NULL) { + CU_DEBUG("Failed to get domain info %s", s.msg); + break; + } + + csi_thread_dom_list_append(thread, dom); + } + + free_domain_list(dom_ptr_list, count); + free(dom_ptr_list); + + return s.rc; +} + +static int csi_domain_event_cb(virConnectPtr conn, + virDomainPtr dom, + int event, + int detail, + void *data) +{ + int cs_event = CS_MODIFIED; + csi_thread_data_t *thread = (csi_thread_data_t *) data; + csi_dom_xml_t *dom_xml = NULL; + char *prefix = class_prefix_name(thread->args->classname); + CMPIStatus s = {CMPI_RC_OK, NULL}; + + CU_DEBUG("Event: Domain %s(%d) event: %d detail: %d\n", + virDomainGetName(dom), virDomainGetID(dom), event, detail); + + switch (event) { + case VIR_DOMAIN_EVENT_DEFINED: + if (detail == VIR_DOMAIN_EVENT_DEFINED_ADDED) { + CU_DEBUG("Domain defined"); + cs_event = CS_CREATED; + dom_xml = csi_dom_xml_new(dom, &s); + } else if (detail == VIR_DOMAIN_EVENT_DEFINED_UPDATED) { + CU_DEBUG("Domain modified"); + cs_event = CS_MODIFIED; + } + + break; + + case VIR_DOMAIN_EVENT_UNDEFINED: + CU_DEBUG("Domain undefined"); + cs_event = CS_DELETED; + break; + + default: /* STARTED, SUSPENDED, RESUMED, STOPPED, SHUTDOWN */ + CU_DEBUG("Domain modified"); + cs_event = CS_MODIFIED; + break; + } + + if (cs_event != CS_CREATED) { + char uuid[VIR_UUID_STRING_BUFLEN] = {0}; + virDomainGetUUIDString(dom, &uuid[0]); + dom_xml = csi_thread_dom_list_find(thread, uuid); + } + + if (dom_xml == NULL) { + CU_DEBUG("Domain not found in current list"); + goto end; + } + + async_ind(thread->args, cs_event, dom_xml, prefix); + + /* Update the domain list accordingly */ + if (event == VIR_DOMAIN_EVENT_DEFINED) { + if (detail == VIR_DOMAIN_EVENT_DEFINED_ADDED) { + csi_thread_dom_list_append(thread, dom_xml); + } else if (detail == VIR_DOMAIN_EVENT_DEFINED_UPDATED) { + free(dom_xml->name); + free(dom_xml->xml); + csi_dom_xml_set(dom_xml, dom, &s); + } + } else if (event == VIR_DOMAIN_EVENT_DEFINED && + detail == VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) { + csi_thread_dom_list_remove(thread, dom_xml); + } + + end: + free(prefix); + return 0; } static CMPI_THREAD_RETURN lifecycle_thread(void *params) { - struct ind_args *args = (struct ind_args *)params; - CMPIContext *context = args->context; - CMPIStatus s; - int prev_count; - int cur_count; - virDomainPtr *tmp_list; - struct dom_xml *cur_xml = NULL; - struct dom_xml *prev_xml = NULL; - virConnectPtr conn; + csi_thread_data_t *thread = (csi_thread_data_t *) params; + struct ind_args *args = thread->args; char *prefix = class_prefix_name(args->classname); - int platform = platform_from_class(args->classname); - if (prefix == NULL || platform == -1) + virConnectPtr conn; + + CMPIStatus s; + int cb_id; + + if (prefix == NULL) goto init_out; conn = connect_by_classname(_BROKER, args->classname, &s); @@ -531,86 +623,66 @@ static CMPI_THREAD_RETURN lifecycle_thread(void *params) goto conn_out; } - pthread_mutex_lock(&lifecycle_mutex); - - CBAttachThread(_BROKER, context); + /* register callback */ + cb_id = virConnectDomainEventRegisterAny(conn, NULL, + VIR_DOMAIN_EVENT_ID_LIFECYCLE, + VIR_DOMAIN_EVENT_CALLBACK(csi_domain_event_cb), + params, csi_free_thread_data); - prev_count = get_domain_list(conn, &tmp_list); - s = doms_to_xml(&prev_xml, tmp_list, prev_count); - if (s.rc != CMPI_RC_OK) - CU_DEBUG("doms_to_xml failed. Attempting to continue."); - free_domain_list(tmp_list, prev_count); - free(tmp_list); - - CU_DEBUG("Entering CSI event loop (%s)", prefix); - while (active_filters[platform] > 0) { - int i; - bool res; - bool failure = false; - - cur_count = get_domain_list(conn, &tmp_list); - s = doms_to_xml(&cur_xml, tmp_list, cur_count); - if (s.rc != CMPI_RC_OK) { - CU_DEBUG("doms_to_xml failed. retry in %d seconds", - FAIL_WAIT_TIME); - failure = true; - goto fail; - } - - free_domain_list(tmp_list, cur_count); - free(tmp_list); - - for (i = 0; i < cur_count; i++) { - res = dom_in_list(cur_xml[i].uuid, prev_count, prev_xml); - if (!res) - async_ind(context, CS_CREATED, - cur_xml[i], prefix, args); - - } - - for (i = 0; i < prev_count; i++) { - res = dom_in_list(prev_xml[i].uuid, cur_count, cur_xml); - if (!res) - async_ind(context, CS_DELETED, - prev_xml[i], prefix, args); - } + if (cb_id == -1) { + CU_DEBUG("Failed to register domain event watch for '%s'", + args->classname) + goto cb_out; + } - for (i = 0; i < prev_count; i++) { - res = dom_changed(prev_xml[i], cur_xml, cur_count); - if (res) { - async_ind(context, CS_MODIFIED, - prev_xml[i], prefix, args); + CBAttachThread(_BROKER, args->context); - } - free_dom_xml(prev_xml[i]); - } + /* Get currently defined domains */ + if (update_domain_list(conn, thread) != CMPI_RC_OK) + goto end; - fail: - if (failure) { - wait_for_event(FAIL_WAIT_TIME); - } else { - free(prev_xml); - prev_xml = cur_xml; - prev_count = cur_count; - wait_for_event(WAIT_TIME); + CU_DEBUG("Entering CSI event loop (%s)", prefix); + while (thread->active_filters > 0) { + if (virEventRunDefaultImpl() < 0) { + virErrorPtr err = virGetLastError(); + CU_DEBUG("Failed to run event loop: %s\n", + err && err->message ? err->message : "Unknown error"); } } CU_DEBUG("Exiting CSI event loop (%s)", prefix); - thread_id[platform] = 0; + CBDetachThread(_BROKER, args->context); + end: + virConnectDomainEventDeregisterAny(conn, cb_id); - pthread_mutex_unlock(&lifecycle_mutex); - stdi_free_ind_args(&args); + cb_out: + + thread->id = 0; + thread->active_filters = 0; + + if (thread->args != NULL) + stdi_free_ind_args(&thread->args); conn_out: virConnectClose(conn); init_out: free(prefix); + return (CMPI_THREAD_RETURN) 0; +} - return NULL; +static int platform_from_class(const char *cn) +{ + if (STARTS_WITH(cn, "Xen")) + return CSI_XEN; + else if (STARTS_WITH(cn, "KVM")) + return CSI_KVM; + else if (STARTS_WITH(cn, "LXC")) + return CSI_LXC; + else + return -1; } static CMPIStatus ActivateFilter(CMPIIndicationMI* mi, @@ -622,17 +694,25 @@ static CMPIStatus ActivateFilter(CMPIIndicationMI* mi, { CMPIStatus s = {CMPI_RC_OK, NULL}; struct std_indication_ctx *_ctx; - struct ind_args *args; + struct ind_args *args = NULL; int platform; + bool error = false; + csi_thread_data_t *thread = NULL; + static int events_registered = 0; CU_DEBUG("ActivateFilter for %s", CLASSNAME(op)); pthread_mutex_lock(&lifecycle_mutex); + if (events_registered == 0) { + events_registered = 1; + virEventRegisterDefaultImpl(); + } + _ctx = (struct std_indication_ctx *)mi->hdl; if (CMIsNullObject(op)) { - cu_statusf(_BROKER, &s, + cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, "No ObjectPath given"); goto out; @@ -647,13 +727,17 @@ static CMPIStatus ActivateFilter(CMPIIndicationMI* mi, goto out; } - if (thread_id[platform] == 0) { - args = malloc(sizeof(struct ind_args)); + thread = &csi_thread_data[platform]; + thread->active_filters += 1; + + if (thread->id == 0) { + args = malloc(sizeof(*args)); if (args == NULL) { CU_DEBUG("Failed to allocate ind_args"); cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, "Unable to allocate ind_args"); + error = true; goto out; } @@ -663,7 +747,7 @@ static CMPIStatus ActivateFilter(CMPIIndicationMI* mi, cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, "Unable to create thread context"); - free(args); + error = true; goto out; } @@ -671,15 +755,17 @@ static CMPIStatus ActivateFilter(CMPIIndicationMI* mi, args->classname = strdup(CLASSNAME(op)); args->_ctx = _ctx; - active_filters[platform] += 1; - - thread_id[platform] = _BROKER->xft->newThread(lifecycle_thread, - args, - 0); - } else - active_filters[platform] += 1; + thread->args = args; + thread->id = _BROKER->xft->newThread(lifecycle_thread, + thread, 0); + } out: + if (error == true) { + thread->active_filters -= 1; + free(args); + } + pthread_mutex_unlock(&lifecycle_mutex); return s; @@ -705,11 +791,11 @@ static CMPIStatus DeActivateFilter(CMPIIndicationMI* mi, goto out; } + pthread_mutex_lock(&lifecycle_mutex); - active_filters[platform] -= 1; + csi_thread_data[platform].active_filters -= 1; pthread_mutex_unlock(&lifecycle_mutex); - pthread_cond_signal(&lifecycle_cond); out: return s; } @@ -736,13 +822,6 @@ static _EI_RTYPE DisableIndications(CMPIIndicationMI* mi, _EI_RET(); } -static CMPIStatus trigger_indication(const CMPIContext *context) -{ - CU_DEBUG("triggered"); - pthread_cond_signal(&lifecycle_cond); - return(CMPIStatus){CMPI_RC_OK, NULL}; -} - DECLARE_FILTER(xen_created, "Xen_ComputerSystemCreatedIndication"); DECLARE_FILTER(xen_deleted, "Xen_ComputerSystemDeletedIndication"); DECLARE_FILTER(xen_modified, "Xen_ComputerSystemModifiedIndication"); @@ -766,126 +845,7 @@ static struct std_ind_filter *filters[] = { NULL, }; -static CMPIInstance *get_prev_inst(const CMPIBroker *broker, - const CMPIInstance *ind, - CMPIStatus *s) -{ - CMPIData data; - CMPIInstance *prev_inst = NULL; - - data = CMGetProperty(ind, "PreviousInstance", s); - if (s->rc != CMPI_RC_OK || CMIsNullValue(data)) { - cu_statusf(broker, s, - CMPI_RC_ERR_NO_SUCH_PROPERTY, - "Unable to get PreviousInstance of the indication"); - goto out; - } - - if (data.type != CMPI_instance) { - cu_statusf(broker, s, - CMPI_RC_ERR_TYPE_MISMATCH, - "Indication SourceInstance is of unexpected type"); - goto out; - } - - prev_inst = data.value.inst; - - out: - return prev_inst; -} - -static CMPIStatus raise_indication(const CMPIBroker *broker, - const CMPIContext *ctx, - const CMPIObjectPath *ref, - const CMPIInstance *ind) -{ - CMPIStatus s = {CMPI_RC_OK, NULL}; - CMPIInstance *prev_inst; - CMPIInstance *src_inst; - CMPIObjectPath *_ref = NULL; - struct std_indication_ctx *_ctx = NULL; - struct ind_args *args = NULL; - char *prefix = NULL; - bool rc; - - if (!lifecycle_enabled) { - cu_statusf(_BROKER, &s, - CMPI_RC_ERR_FAILED, - "CSI not enabled, skipping indication delivery"); - goto out; - } - - prev_inst = get_prev_inst(broker, ind, &s); - if (s.rc != CMPI_RC_OK || CMIsNullObject(prev_inst)) - goto out; - - _ref = CMGetObjectPath(prev_inst, &s); - if (s.rc != CMPI_RC_OK) { - cu_statusf(broker, &s, - CMPI_RC_ERR_FAILED, - "Unable to get a reference to the guest"); - goto out; - } - - /* FIXME: This is a Pegasus work around. Pegsus loses the namespace - when an ObjectPath is pulled from an instance */ - if (STREQ(NAMESPACE(_ref), "")) - CMSetNameSpace(_ref, "root/virt"); - - s = get_domain_by_ref(broker, _ref, &src_inst); - if (s.rc != CMPI_RC_OK || CMIsNullObject(src_inst)) - goto out; - - _ctx = malloc(sizeof(struct std_indication_ctx)); - if (_ctx == NULL) { - cu_statusf(broker, &s, - CMPI_RC_ERR_FAILED, - "Unable to allocate indication context"); - goto out; - } - - _ctx->brkr = broker; - _ctx->handler = NULL; - _ctx->filters = filters; - _ctx->enabled = lifecycle_enabled; - - args = malloc(sizeof(struct ind_args)); - if (args == NULL) { - cu_statusf(broker, &s, - CMPI_RC_ERR_FAILED, - "Unable to allocate ind_args"); - goto out; - } - - args->ns = strdup(NAMESPACE(_ref)); - args->classname = strdup(CLASSNAME(_ref)); - args->_ctx = _ctx; - - prefix = class_prefix_name(args->classname); - - rc = _do_indication(broker, ctx, prev_inst, src_inst, - CS_MODIFIED, prefix, args); - - if (!rc) { - cu_statusf(_BROKER, &s, - CMPI_RC_ERR_FAILED, - "Unable to generate indication"); - } - - out: - if (args != NULL) - stdi_free_ind_args(&args); - - if (_ctx != NULL) - free(_ctx); - - free(prefix); - return s; -} - static struct std_indication_handler csi = { - .raise_fn = raise_indication, - .trigger_fn = trigger_indication, .activate_fn = ActivateFilter, .deactivate_fn = DeActivateFilter, .enable_fn = EnableIndications, @@ -896,10 +856,10 @@ DEFAULT_IND_CLEANUP(); DEFAULT_AF(); DEFAULT_MP(); -STDI_IndicationMIStub(, +STDI_IndicationMIStub(, Virt_ComputerSystemIndicationProvider, _BROKER, - libvirt_cim_init(), + libvirt_cim_init(), &csi, filters); diff --git a/src/Virt_ComputerSystemIndication.h b/src/Virt_ComputerSystemIndication.h index 0f8f1b7..594c3ed 100644 --- a/src/Virt_ComputerSystemIndication.h +++ b/src/Virt_ComputerSystemIndication.h @@ -24,11 +24,6 @@ #include #include -bool cs_lifecycle_indication(const CMPIBroker *broker, - const CMPIContext *ctx, - const CMPIObjectPath *newsystem, - char *type); - void set_source_inst_props(const CMPIBroker *broker, const CMPIContext *context, const CMPIObjectPath *ref, diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c index 4d26429..46bc9b5 100644 --- a/src/Virt_VirtualSystemManagementService.c +++ b/src/Virt_VirtualSystemManagementService.c @@ -1894,7 +1894,7 @@ static CMPIStatus raise_rasd_indication(const CMPIContext *context, CMPIObjectPath *op = NULL; int i; - CU_DEBUG("raise_rasd_indication"); + CU_DEBUG("raise_rasd_indication %s", base_type); type = get_typed_class(CLASSNAME(ref), base_type); @@ -2105,22 +2105,6 @@ static CMPIInstance *create_system(const CMPIContext *context, return inst; } -static bool trigger_indication(const CMPIContext *context, - const char *base_type, - const CMPIObjectPath *ref) -{ - char *type; - CMPIStatus s; - - type = get_typed_class(CLASSNAME(ref), base_type); - - s = stdi_trigger_indication(_BROKER, context, type, NAMESPACE(ref)); - - free(type); - - return s.rc == CMPI_RC_OK; -} - static CMPIStatus define_system(CMPIMethodMI *self, const CMPIContext *context, const CMPIResult *results, @@ -2156,9 +2140,6 @@ static CMPIStatus define_system(CMPIMethodMI *self, CMAddArg(argsout, "ResultingSystem", &result, CMPI_ref); } - trigger_indication(context, - "ComputerSystemCreatedIndication", - reference); out: if (s.rc == CMPI_RC_OK) rc = CIM_SVPC_RETURN_COMPLETED; @@ -2261,9 +2242,6 @@ error: NULL, reference, &list); - trigger_indication(context, - "ComputerSystemDeletedIndication", - reference); } virDomainFree(dom); @@ -2345,12 +2323,8 @@ static CMPIStatus update_system_settings(const CMPIContext *context, connect_and_create(xml, ref, &s); } - if (s.rc == CMPI_RC_OK) { + if (s.rc == CMPI_RC_OK) set_autostart(vssd, ref, dom); - trigger_indication(context, - "ComputerSystemModifiedIndication", - ref); - } out: free(xml); -- 1.7.4.4 From eblima at linux.vnet.ibm.com Mon Jan 2 19:17:41 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Mon, 02 Jan 2012 17:17:41 -0200 Subject: [Libvirt-cim] [PATCHv2] ComputerSystemIndication: Support libvirt domain events In-Reply-To: <1325530374-31634-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1325530374-31634-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F0202D5.2070603@linux.vnet.ibm.com> On 01/02/2012 04:52 PM, Eduardo Lima (Etrunko) wrote: > From: Eduardo Lima (Etrunko) > > Port current implementation to use domain events implementation provided by > libvirt. It requires libvirt version 0.9.0 or newer, when the > virEventRegisterDefaultImpl and virEventRunDefaultImpl API's were introduced. > > Now that all events are generated by libvirt itself, we don't need to trigger > them manually anymore. Thus, this patch also removes trigger and raise calls > from VirtualSystemManagementService and ComputerSystem providers. > > Differences from v1: > - Move call to virRegisterDefaultImpl() to the provider code with protection > to ensure it is called only once. > - Call CBDetachThread() before exiting the lifecycle thread. This version looks much more stable than the first one. I have run the full cimtest suite many times, but it still looks like it interferes with the ElementConforms group. -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From cvincent at linux.vnet.ibm.com Tue Jan 3 02:05:57 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Mon, 02 Jan 2012 21:05:57 -0500 Subject: [Libvirt-cim] Release of libvirt-cim-0.6 Message-ID: <4F026285.8010406@linux.vnet.ibm.com> I'm happy announce the release of libvirt-cim-0.6. The new release is available at: ftp://libvirt.org/libvirt-cim/libvirt-cim-0.6.0.tar.gz libvirt-cim-0.6: * ComputerSystemIndication: Support libvirt domain events (Eduardo Lima (Etrunko)) * Network QoS Patch2 (Gareth S. Bestor) * cpu cgroup patch 2 (Gareth S. Bestor) * Build: Make 'make distcheck' happy (Eduardo Lima (Etrunko)) * Build: Remove tests subdirs from source (Eduardo Lima (Etrunko) -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com _______________________________________________ Libvirt-cim mailing list Libvirt-cim at redhat.com https://www.redhat.com/mailman/listinfo/libvirt-cim From cvincent at linux.vnet.ibm.com Tue Jan 3 05:39:06 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Tue, 03 Jan 2012 00:39:06 -0500 Subject: [Libvirt-cim] [PATCHv2] ComputerSystemIndication: Support libvirt domain events In-Reply-To: <1325530374-31634-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1325530374-31634-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F02947A.2070901@linux.vnet.ibm.com> Thanks for the quick turnaround. +1 and pushed. BTW - I'm still curious a) why the original code was problematic and b) how the current code interacts with non-indication providers. And, we still require a follow-on patch with an external polling loop for "legacy" support. On 01/02/2012 01:52 PM, Eduardo Lima (Etrunko) wrote: > From: Eduardo Lima (Etrunko) > > Port current implementation to use domain events implementation provided by > libvirt. It requires libvirt version 0.9.0 or newer, when the > virEventRegisterDefaultImpl and virEventRunDefaultImpl API's were introduced. > > Now that all events are generated by libvirt itself, we don't need to trigger > them manually anymore. Thus, this patch also removes trigger and raise calls > from VirtualSystemManagementService and ComputerSystem providers. > > Differences from v1: > - Move call to virRegisterDefaultImpl() to the provider code with protection > to ensure it is called only once. > - Call CBDetachThread() before exiting the lifecycle thread. > > Signed-off-by: Eduardo Lima (Etrunko) > --- > acinclude.m4 | 2 +- > libvirt-cim.spec.in | 4 +- > src/Virt_ComputerSystem.c | 51 +-- > src/Virt_ComputerSystemIndication.c | 766 ++++++++++++++--------------- > src/Virt_ComputerSystemIndication.h | 5 - > src/Virt_VirtualSystemManagementService.c | 30 +- > 6 files changed, 378 insertions(+), 480 deletions(-) > > diff --git a/acinclude.m4 b/acinclude.m4 > index e313891..e0f76b6 100644 > --- a/acinclude.m4 > +++ b/acinclude.m4 > @@ -243,7 +243,7 @@ AC_DEFUN([CHECK_LIBCU], > > AC_DEFUN([CHECK_LIBVIRT], > [ > - PKG_CHECK_MODULES([LIBVIRT], [libvirt>= 0.3.2]) > + PKG_CHECK_MODULES([LIBVIRT], [libvirt>= 0.9.0]) > AC_SUBST([LIBVIRT_CFLAGS]) > AC_SUBST([LIBVIRT_LIBS]) > CPPFLAGS="$CPPFLAGS $LIBVIRT_CFLAGS" > diff --git a/libvirt-cim.spec.in b/libvirt-cim.spec.in > index 5b7267b..f3289db 100644 > --- a/libvirt-cim.spec.in > +++ b/libvirt-cim.spec.in > @@ -10,12 +10,12 @@ Source: libvirt-cim-%{version}.tar.gz > BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root > URL: http://libvirt.org/CIM/ > Requires: libxml2>= 2.6.0 > -Requires: libvirt>= 0.6.3 > +Requires: libvirt>= 0.9.0 > Requires: unzip > Requires: tog-pegasus > BuildRequires: libcmpiutil>= 0.5.4 > BuildRequires: tog-pegasus-devel > -BuildRequires: libvirt-devel>= 0.6.3 > +BuildRequires: libvirt-devel>= 0.9.0 > > # In RHEL5 uuid-devel is provided by e2fsprogs > %if 0%{?el5} > diff --git a/src/Virt_ComputerSystem.c b/src/Virt_ComputerSystem.c > index 098b07a..582253a 100644 > --- a/src/Virt_ComputerSystem.c > +++ b/src/Virt_ComputerSystem.c > @@ -492,6 +492,7 @@ static CMPIStatus set_properties(const CMPIBroker *broker, > } > > if (!set_name_from_dom(dom, instance)) { > + CU_DEBUG("Unable to get domain name"); > virt_set_status(broker,&s, > CMPI_RC_ERR_FAILED, > virDomainGetConnect(dom), > @@ -500,6 +501,7 @@ static CMPIStatus set_properties(const CMPIBroker *broker, > } > > if (!set_uuid_from_dom(dom, instance,&uuid)) { > + CU_DEBUG("Unable to get domain uuid"); > virt_set_status(broker,&s, > CMPI_RC_ERR_FAILED, > virDomainGetConnect(dom), > @@ -514,6 +516,7 @@ static CMPIStatus set_properties(const CMPIBroker *broker, > } > > if (!set_state_from_dom(broker, dom, instance)) { > + CU_DEBUG("Unable to get domain info"); > virt_set_status(broker,&s, > CMPI_RC_ERR_FAILED, > virDomainGetConnect(dom), > @@ -660,6 +663,7 @@ CMPIStatus get_domain_by_name(const CMPIBroker *broker, > > conn = connect_by_classname(broker, CLASSNAME(reference),&s); > if (conn == NULL) { > + CU_DEBUG("No such instance"); > cu_statusf(broker,&s, > CMPI_RC_ERR_NOT_FOUND, > "No such instance."); > @@ -668,6 +672,7 @@ CMPIStatus get_domain_by_name(const CMPIBroker *broker, > > dom = virDomainLookupByName(conn, name); > if (dom == NULL) { > + CU_DEBUG("Domain '%s' does not exist", name); > virt_set_status(broker,&s, > CMPI_RC_ERR_NOT_FOUND, > conn, > @@ -681,8 +686,10 @@ CMPIStatus get_domain_by_name(const CMPIBroker *broker, > conn, > dom, > &inst); > - if (s.rc != CMPI_RC_OK) > + if (s.rc != CMPI_RC_OK) { > + CU_DEBUG("Unable to retrieve instance from domain"); > goto out; > + } > > *_inst = inst; > > @@ -766,39 +773,6 @@ DEFAULT_DI(); > DEFAULT_EQ(); > DEFAULT_INST_CLEANUP(); > > -static bool trigger_mod_indication(const CMPIContext *context, > - CMPIInstance *prev_inst, > - const CMPIObjectPath *ref) > -{ > - CMPIStatus s = {CMPI_RC_OK, NULL}; > - const char *ind_name = "ComputerSystemModifiedIndication"; > - CMPIInstance *ind = NULL; > - char *type = NULL; > - > - CU_DEBUG("Preparing ComputerSystem indication"); > - > - ind = get_typed_instance(_BROKER, > - CLASSNAME(ref), > - ind_name, > - NAMESPACE(ref)); > - if (ind == NULL) { > - CU_DEBUG("Failed to create ind '%s'", ind_name); > - goto out; > - } > - > - CU_DEBUG("Setting PreviousInstance"); > - CMSetProperty(ind, "PreviousInstance", > - (CMPIValue *)&prev_inst, CMPI_instance); > - > - type = get_typed_class(CLASSNAME(ref), ind_name); > - > - s = stdi_raise_indication(_BROKER, context, type, NAMESPACE(ref), ind); > - > - out: > - free(type); > - return s.rc == CMPI_RC_OK; > -} > - > static int xen_scheduler_params(struct infostore_ctx *ctx, > virSchedParameter **params) > { > @@ -1253,7 +1227,6 @@ static CMPIStatus state_change(CMPIMethodMI *self, > int ret; > const char *name = NULL; > uint32_t rc = 1; > - bool ind_rc; > > ret = cu_get_u16_arg(argsin, "RequestedState",&state); > if (ret != CMPI_RC_OK) { > @@ -1282,13 +1255,9 @@ static CMPIStatus state_change(CMPIMethodMI *self, > > s = __state_change(name, state, reference); > > - if (s.rc == CMPI_RC_OK) { > - ind_rc= trigger_mod_indication(context, prev_inst, reference); > - if (!ind_rc) > - CU_DEBUG("Unable to trigger indication"); > - > + if (s.rc == CMPI_RC_OK) > rc = 0; > - } > + > out: > CMReturnData(results,&rc, CMPI_uint32); > > diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c > index a00444d..eb1a71c 100644 > --- a/src/Virt_ComputerSystemIndication.c > +++ b/src/Virt_ComputerSystemIndication.c > @@ -25,13 +25,13 @@ > #include > #include > #include > -#include > > #include > #include > #include > > #include > +#include > > #include > #include > @@ -44,158 +44,187 @@ > #include "Virt_ComputerSystemIndication.h" > #include "Virt_HostSystem.h" > > -static const CMPIBroker *_BROKER; > > #define CSI_NUM_PLATFORMS 3 > -enum CSI_PLATFORMS {CSI_XEN, > - CSI_KVM, > - CSI_LXC, > +enum CSI_PLATFORMS { > + CSI_XEN, > + CSI_KVM, > + CSI_LXC, > }; > > -static CMPI_THREAD_TYPE thread_id[CSI_NUM_PLATFORMS]; > -static int active_filters[CSI_NUM_PLATFORMS]; > - > -enum CS_EVENTS {CS_CREATED, > - CS_DELETED, > - CS_MODIFIED, > +#define CS_NUM_EVENTS 3 > +enum CS_EVENTS { > + CS_CREATED, > + CS_DELETED, > + CS_MODIFIED, > }; > > -static pthread_cond_t lifecycle_cond = PTHREAD_COND_INITIALIZER; > -static pthread_mutex_t lifecycle_mutex = PTHREAD_MUTEX_INITIALIZER; > -static bool lifecycle_enabled = 0; > - > -#define WAIT_TIME 60 > -#define FAIL_WAIT_TIME 2 > - > -struct dom_xml { > +typedef struct _csi_dom_xml_t csi_dom_xml_t; > +struct _csi_dom_xml_t { > char uuid[VIR_UUID_STRING_BUFLEN]; > + char *name; > char *xml; > - enum {DOM_OFFLINE, > - DOM_ONLINE, > - DOM_PAUSED, > - DOM_CRASHED, > - DOM_GONE, > - } state; > + csi_dom_xml_t *next; > + csi_dom_xml_t *prev; > +}; > + > +typedef struct _csi_thread_data_t csi_thread_data_t; > +struct _csi_thread_data_t { > + CMPI_THREAD_TYPE id; > + int active_filters; > + int dom_count; > + csi_dom_xml_t *dom_list; > + struct ind_args *args; > }; > > -static void free_dom_xml (struct dom_xml dom) > +static const CMPIBroker *_BROKER; > +static pthread_mutex_t lifecycle_mutex = PTHREAD_MUTEX_INITIALIZER; > +static bool lifecycle_enabled = false; > +static csi_thread_data_t csi_thread_data[CSI_NUM_PLATFORMS] = {{0}, {0}, {0}}; > + > +/* > + * Domain list manipulation > + */ > +static void csi_dom_xml_free(csi_dom_xml_t *dom) > { > - free(dom.xml); > + free(dom->xml); > + free(dom->name); > + free(dom); > } > > -static char *sys_name_from_xml(char *xml) > +static int csi_dom_xml_set(csi_dom_xml_t *dom, virDomainPtr dom_ptr, CMPIStatus *s) > { > - char *tmp = NULL; > - char *name = NULL; > - int rc; > + const char *name; > > - tmp = strstr(xml, ""); > - if (tmp == NULL) > - goto out; > + name = virDomainGetName(dom_ptr); > + if (name == NULL) { > + cu_statusf(_BROKER, s, > + CMPI_RC_ERR_FAILED, > + "Failed to get domain name"); > + return -1; > + } > > - rc = sscanf(tmp, "%a[^<]s",&name); > - if (rc != 1) > - name = NULL; > + dom->name = strdup(name); > + > + /* xml */ > + dom->xml = virDomainGetXMLDesc(dom_ptr, VIR_DOMAIN_XML_SECURE); > + if (dom->xml == NULL) { > + cu_statusf(_BROKER, s, > + CMPI_RC_ERR_FAILED, > + "Failed to get xml desc"); > + return -1; > + } > > - out: > - return name; > + return 0; > } > > -static int dom_state(virDomainPtr dom) > +static csi_dom_xml_t *csi_dom_xml_new(virDomainPtr dom_ptr, CMPIStatus *s) > { > - virDomainInfo info; > - int ret; > + int rc; > + csi_dom_xml_t *dom; > > - ret = virDomainGetInfo(dom,&info); > - if (ret != 0) > - return DOM_GONE; > + dom = calloc(1, sizeof(*dom)); > + if (dom == NULL) > + return NULL; > > - switch (info.state) { > - case VIR_DOMAIN_NOSTATE: > - case VIR_DOMAIN_RUNNING: > - case VIR_DOMAIN_BLOCKED: > - return DOM_ONLINE; > + /* uuid */ > + rc = virDomainGetUUIDString(dom_ptr, dom->uuid); > + if (rc == -1) { > + cu_statusf(_BROKER, s, > + CMPI_RC_ERR_FAILED, > + "Failed to get domain UUID"); > + goto error; > + } > > - case VIR_DOMAIN_PAUSED: > - return DOM_PAUSED; > + if (csi_dom_xml_set(dom, dom_ptr, s) == -1) > + goto error; > > - case VIR_DOMAIN_SHUTOFF: > - return DOM_OFFLINE; > + return dom; > > - case VIR_DOMAIN_CRASHED: > - return DOM_CRASHED; > + error: > + csi_dom_xml_free(dom); > + return NULL; > +} > > - default: > - return DOM_GONE; > - }; > +static void csi_thread_dom_list_append(csi_thread_data_t *thread, > + csi_dom_xml_t *dom) > +{ > + /* empty list */ > + if (thread->dom_list == NULL) { > + dom->next = dom->prev = dom; > + thread->dom_list = dom; > + goto end; > + } > + > + dom->next = thread->dom_list; > + dom->prev = thread->dom_list->prev; > + > + thread->dom_list->prev->next = dom; > + thread->dom_list->prev = dom; > + > + end: > + thread->dom_count += 1; > } > > -static CMPIStatus doms_to_xml(struct dom_xml **dom_xml_list, > - virDomainPtr *dom_ptr_list, > - int dom_ptr_count) > +static csi_dom_xml_t *csi_thread_dom_list_find(csi_thread_data_t *thread, > + const char *uuid) > { > - int i; > - int rc; > - CMPIStatus s = {CMPI_RC_OK, NULL}; > + csi_dom_xml_t *dom; > > - *dom_xml_list = calloc(dom_ptr_count, sizeof(struct dom_xml)); > - for (i = 0; i< dom_ptr_count; i++) { > - rc = virDomainGetUUIDString(dom_ptr_list[i], > - (*dom_xml_list)[i].uuid); > - if (rc == -1) { > - cu_statusf(_BROKER,&s, > - CMPI_RC_ERR_FAILED, > - "Failed to get UUID"); > - /* If any domain fails, we fail. */ > - break; > - } > + if (thread->dom_list == NULL) > + return NULL; > > - (*dom_xml_list)[i].xml = virDomainGetXMLDesc(dom_ptr_list[i], > - VIR_DOMAIN_XML_SECURE); > - if ((*dom_xml_list)[i].xml == NULL) { > - cu_statusf(_BROKER,&s, > - CMPI_RC_ERR_FAILED, > - "Failed to get xml desc"); > - break; > - } > + dom = thread->dom_list; > + > + do { > + if (STREQ(dom->uuid, uuid)) > + return dom; > > - (*dom_xml_list)[i].state = dom_state(dom_ptr_list[i]); > + dom = dom->next; > + } while (dom != thread->dom_list); > + > + return NULL; > +} > + > +static void csi_thread_dom_list_remove(csi_thread_data_t *thread, > + csi_dom_xml_t *dom) > +{ > + if (dom->next == dom) { /* Only one node */ > + thread->dom_list = NULL; > + } else { > + if (thread->dom_list == dom) /* First node */ > + thread->dom_list = dom->next; > + > + dom->prev->next = dom->next; > + dom->next->prev = dom->prev; > } > - > - return s; > + > + thread->dom_count -= 1; > + > + csi_dom_xml_free(dom); > } > > -static bool dom_changed(struct dom_xml prev_dom, > - struct dom_xml *cur_xml, > - int cur_count) > +static void csi_thread_dom_list_free(csi_thread_data_t *thread) > { > - int i; > - bool ret = false; > - > - for (i = 0; i< cur_count; i++) { > - if (strcmp(cur_xml[i].uuid, prev_dom.uuid) != 0) > - continue; > - > - if (strcmp(cur_xml[i].xml, prev_dom.xml) != 0) { > - CU_DEBUG("Domain config changed"); > - ret = true; > - } > + while(thread->dom_list != NULL) > + csi_thread_dom_list_remove(thread, thread->dom_list); > +} > > - if (prev_dom.state != cur_xml[i].state) { > - CU_DEBUG("Domain state changed"); > - ret = true; > - } > +static void csi_free_thread_data(void *data) > +{ > + csi_thread_data_t *thread = (csi_thread_data_t *) data; > > - break; > - } > - > - return ret; > + if (data == NULL) > + return; > + > + csi_thread_dom_list_free(thread); > + stdi_free_ind_args(&thread->args); > } > > void set_source_inst_props(const CMPIBroker *broker, > - const CMPIContext *context, > - const CMPIObjectPath *ref, > - CMPIInstance *ind) > + const CMPIContext *context, > + const CMPIObjectPath *ref, > + CMPIInstance *ind) > { > const char *host; > const char *hostccn; > @@ -225,7 +254,7 @@ static bool _do_indication(const CMPIBroker *broker, > CMPIInstance *prev_inst, > CMPIInstance *affected_inst, > int ind_type, > - char *prefix, > + const char *prefix, > struct ind_args *args) > { > const char *ind_type_name = NULL; > @@ -254,10 +283,10 @@ static bool _do_indication(const CMPIBroker *broker, > ind_type_name, > args->ns); > > - /* Generally report errors and hope to continue, since we have no one > + /* Generally report errors and hope to continue, since we have no one > to actually return status to. */ > if (ind == NULL) { > - CU_DEBUG("Failed to create ind, type '%s:%s_%s'", > + CU_DEBUG("Failed to create ind, type '%s:%s_%s'", > args->ns, > prefix, > ind_type_name); > @@ -279,14 +308,15 @@ static bool _do_indication(const CMPIBroker *broker, > CU_DEBUG("problem getting affected_op: '%s'", s.msg); > goto out; > } > + > CMSetNameSpace(affected_op, args->ns); > > uuid = CMGetProperty(affected_inst, "UUID",&s); > - CMSetProperty(ind, "IndicationIdentifier", > + CMSetProperty(ind, "IndicationIdentifier", > (CMPIValue *)&(uuid.value), CMPI_string); > > timestamp = CMNewDateTime(broker,&s); > - CMSetProperty(ind, "IndicationTime", > + CMSetProperty(ind, "IndicationTime", > (CMPIValue *)×tamp, CMPI_dateTime); > > if (ind_type == CS_MODIFIED) { > @@ -313,34 +343,6 @@ static bool _do_indication(const CMPIBroker *broker, > return ret; > } > > -static bool wait_for_event(int wait_time) > -{ > - struct timespec timeout; > - int ret; > - > - > - clock_gettime(CLOCK_REALTIME,&timeout); > - timeout.tv_sec += wait_time; > - > - ret = pthread_cond_timedwait(&lifecycle_cond, > -&lifecycle_mutex, > -&timeout); > - > - return true; > -} > - > -static bool dom_in_list(char *uuid, int count, struct dom_xml *list) > -{ > - int i; > - > - for (i = 0; i< count; i++) { > - if (STREQ(uuid, list[i].uuid)) > - return true; > - } > - > - return false; > -} > - > static bool set_instance_state(CMPIInstance *instance) > { > CMPIStatus s = {CMPI_RC_OK, NULL}; > @@ -356,7 +358,7 @@ static bool set_instance_state(CMPIInstance *instance) > cim_state_other = CMNewString(_BROKER, "Guest destroyed",&s); > CMSetProperty(instance, "EnabledState", > (CMPIValue *)&cim_state, CMPI_uint16); > - CMSetProperty(instance, "OtherEnabledState", > + CMSetProperty(instance, "OtherEnabledState", > (CMPIValue *)&cim_state_other, CMPI_string); > > health_state = CIM_HEALTH_UNKNOWN; > @@ -382,13 +384,13 @@ static bool set_instance_state(CMPIInstance *instance) > req_state = CIM_STATE_UNKNOWN; > CMSetProperty(instance, "RequestedState", > (CMPIValue *)&req_state, CMPI_uint16); > - > + > return true; > } > > -static bool create_deleted_guest_inst(char *xml, > - char *namespace, > - char *prefix, > +static bool create_deleted_guest_inst(const char *xml, > + const char *namespace, > + const char *prefix, > CMPIInstance **inst) > { > bool rc = false; > @@ -402,18 +404,18 @@ static bool create_deleted_guest_inst(char *xml, > goto out; > } > > - s = instance_from_dominfo(_BROKER, > - namespace, > + s = instance_from_dominfo(_BROKER, > + namespace, > prefix, > - dominfo, > - inst); > + dominfo, > + inst); > if (s.rc != CMPI_RC_OK) { > CU_DEBUG("instance from domain info error: %s", s.msg); > goto out; > } > > rc = set_instance_state(*inst); > - if (!rc) > + if (!rc) > CU_DEBUG("Error setting instance state"); > > out: > @@ -422,14 +424,12 @@ static bool create_deleted_guest_inst(char *xml, > return rc; > } > > -static bool async_ind(CMPIContext *context, > +static bool async_ind(struct ind_args *args, > int ind_type, > - struct dom_xml prev_dom, > - char *prefix, > - struct ind_args *args) > + csi_dom_xml_t *dom, > + const char *prefix) > { > bool rc = false; > - char *name = NULL; > char *cn = NULL; > CMPIObjectPath *op; > CMPIInstance *prev_inst; > @@ -441,13 +441,6 @@ static bool async_ind(CMPIContext *context, > return false; > } > > - name = sys_name_from_xml(prev_dom.xml); > - CU_DEBUG("Name for system: '%s'", name); > - if (name == NULL) { > - rc = false; > - goto out; > - } > - > cn = get_typed_class(prefix, "ComputerSystem"); > > op = CMNewObjectPath(_BROKER, args->ns, cn,&s); > @@ -457,15 +450,32 @@ static bool async_ind(CMPIContext *context, > } > > if (ind_type == CS_CREATED || ind_type == CS_MODIFIED) { > - s = get_domain_by_name(_BROKER, op, name,&affected_inst); > - if (s.rc != CMPI_RC_OK) { > + s = get_domain_by_name(_BROKER, op, dom->name,&affected_inst); > + > + /* If domain is not found, we create the instance from the data > + previously stored */ > + if (s.rc == CMPI_RC_ERR_NOT_FOUND) { > + rc = create_deleted_guest_inst(dom->xml, > + args->ns, > + prefix, > +&affected_inst); > + if (!rc) { > + CU_DEBUG("Could not recreate guest instance"); > + goto out; > + } > + > + s.rc = CMPI_RC_OK; > + } > + > + if (s.rc != CMPI_RC_OK) { > CU_DEBUG("domain by name error"); > goto out; > } > + > } else if (ind_type == CS_DELETED) { > - rc = create_deleted_guest_inst(prev_dom.xml, > - args->ns, > - prefix, > + rc = create_deleted_guest_inst(dom->xml, > + args->ns, > + prefix, > &affected_inst); > if (!rc) { > CU_DEBUG("Could not recreate guest instance"); > @@ -476,52 +486,134 @@ static bool async_ind(CMPIContext *context, > goto out; > } > > - /* FIXME: We are unable to get the previous CS instance after it has > + /* FIXME: We are unable to get the previous CS instance after it has > been modified. Consider keeping track of the previous > - state in the place we keep track of the requested state */ > + state in the place we keep track of the requested state */ > prev_inst = affected_inst; > > - CMSetProperty(affected_inst, "Name", > - (CMPIValue *)name, CMPI_chars); > + CMSetProperty(affected_inst, "Name", > + (CMPIValue *) dom->name, CMPI_chars); > CMSetProperty(affected_inst, "UUID", > - (CMPIValue *)prev_dom.uuid, CMPI_chars); > + (CMPIValue *) dom->uuid, CMPI_chars); > > - rc = _do_indication(_BROKER, context, prev_inst, affected_inst, > + rc = _do_indication(_BROKER, args->context, prev_inst, affected_inst, > ind_type, prefix, args); > > out: > free(cn); > - free(name); > return rc; > } > > -static int platform_from_class(const char *cn) > +static int update_domain_list(virConnectPtr conn, csi_thread_data_t *thread) > { > - if (STARTS_WITH(cn, "Xen")) > - return CSI_XEN; > - else if (STARTS_WITH(cn, "KVM")) > - return CSI_KVM; > - else if (STARTS_WITH(cn, "LXC")) > - return CSI_LXC; > - else > - return -1; > + virDomainPtr *dom_ptr_list; > + csi_dom_xml_t *dom; > + CMPIStatus s = {CMPI_RC_OK, NULL}; > + int i, count; > + > + csi_thread_dom_list_free(thread); > + > + count = get_domain_list(conn,&dom_ptr_list); > + > + for (i = 0; i< count; i++) { > + dom = csi_dom_xml_new(dom_ptr_list[i],&s); > + if (dom == NULL) { > + CU_DEBUG("Failed to get domain info %s", s.msg); > + break; > + } > + > + csi_thread_dom_list_append(thread, dom); > + } > + > + free_domain_list(dom_ptr_list, count); > + free(dom_ptr_list); > + > + return s.rc; > +} > + > +static int csi_domain_event_cb(virConnectPtr conn, > + virDomainPtr dom, > + int event, > + int detail, > + void *data) > +{ > + int cs_event = CS_MODIFIED; > + csi_thread_data_t *thread = (csi_thread_data_t *) data; > + csi_dom_xml_t *dom_xml = NULL; > + char *prefix = class_prefix_name(thread->args->classname); > + CMPIStatus s = {CMPI_RC_OK, NULL}; > + > + CU_DEBUG("Event: Domain %s(%d) event: %d detail: %d\n", > + virDomainGetName(dom), virDomainGetID(dom), event, detail); > + > + switch (event) { > + case VIR_DOMAIN_EVENT_DEFINED: > + if (detail == VIR_DOMAIN_EVENT_DEFINED_ADDED) { > + CU_DEBUG("Domain defined"); > + cs_event = CS_CREATED; > + dom_xml = csi_dom_xml_new(dom,&s); > + } else if (detail == VIR_DOMAIN_EVENT_DEFINED_UPDATED) { > + CU_DEBUG("Domain modified"); > + cs_event = CS_MODIFIED; > + } > + > + break; > + > + case VIR_DOMAIN_EVENT_UNDEFINED: > + CU_DEBUG("Domain undefined"); > + cs_event = CS_DELETED; > + break; > + > + default: /* STARTED, SUSPENDED, RESUMED, STOPPED, SHUTDOWN */ > + CU_DEBUG("Domain modified"); > + cs_event = CS_MODIFIED; > + break; > + } > + > + if (cs_event != CS_CREATED) { > + char uuid[VIR_UUID_STRING_BUFLEN] = {0}; > + virDomainGetUUIDString(dom,&uuid[0]); > + dom_xml = csi_thread_dom_list_find(thread, uuid); > + } > + > + if (dom_xml == NULL) { > + CU_DEBUG("Domain not found in current list"); > + goto end; > + } > + > + async_ind(thread->args, cs_event, dom_xml, prefix); > + > + /* Update the domain list accordingly */ > + if (event == VIR_DOMAIN_EVENT_DEFINED) { > + if (detail == VIR_DOMAIN_EVENT_DEFINED_ADDED) { > + csi_thread_dom_list_append(thread, dom_xml); > + } else if (detail == VIR_DOMAIN_EVENT_DEFINED_UPDATED) { > + free(dom_xml->name); > + free(dom_xml->xml); > + csi_dom_xml_set(dom_xml, dom,&s); > + } > + } else if (event == VIR_DOMAIN_EVENT_DEFINED&& > + detail == VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) { > + csi_thread_dom_list_remove(thread, dom_xml); > + } > + > + end: > + free(prefix); > + return 0; > } > > static CMPI_THREAD_RETURN lifecycle_thread(void *params) > { > - struct ind_args *args = (struct ind_args *)params; > - CMPIContext *context = args->context; > - CMPIStatus s; > - int prev_count; > - int cur_count; > - virDomainPtr *tmp_list; > - struct dom_xml *cur_xml = NULL; > - struct dom_xml *prev_xml = NULL; > - virConnectPtr conn; > + csi_thread_data_t *thread = (csi_thread_data_t *) params; > + struct ind_args *args = thread->args; > char *prefix = class_prefix_name(args->classname); > - int platform = platform_from_class(args->classname); > > - if (prefix == NULL || platform == -1) > + virConnectPtr conn; > + > + CMPIStatus s; > + int cb_id; > + > + if (prefix == NULL) > goto init_out; > > conn = connect_by_classname(_BROKER, args->classname,&s); > @@ -531,86 +623,66 @@ static CMPI_THREAD_RETURN lifecycle_thread(void *params) > goto conn_out; > } > > - pthread_mutex_lock(&lifecycle_mutex); > - > - CBAttachThread(_BROKER, context); > + /* register callback */ > + cb_id = virConnectDomainEventRegisterAny(conn, NULL, > + VIR_DOMAIN_EVENT_ID_LIFECYCLE, > + VIR_DOMAIN_EVENT_CALLBACK(csi_domain_event_cb), > + params, csi_free_thread_data); > > - prev_count = get_domain_list(conn,&tmp_list); > - s = doms_to_xml(&prev_xml, tmp_list, prev_count); > - if (s.rc != CMPI_RC_OK) > - CU_DEBUG("doms_to_xml failed. Attempting to continue."); > - free_domain_list(tmp_list, prev_count); > - free(tmp_list); > - > - CU_DEBUG("Entering CSI event loop (%s)", prefix); > - while (active_filters[platform]> 0) { > - int i; > - bool res; > - bool failure = false; > - > - cur_count = get_domain_list(conn,&tmp_list); > - s = doms_to_xml(&cur_xml, tmp_list, cur_count); > - if (s.rc != CMPI_RC_OK) { > - CU_DEBUG("doms_to_xml failed. retry in %d seconds", > - FAIL_WAIT_TIME); > - failure = true; > - goto fail; > - } > - > - free_domain_list(tmp_list, cur_count); > - free(tmp_list); > - > - for (i = 0; i< cur_count; i++) { > - res = dom_in_list(cur_xml[i].uuid, prev_count, prev_xml); > - if (!res) > - async_ind(context, CS_CREATED, > - cur_xml[i], prefix, args); > - > - } > - > - for (i = 0; i< prev_count; i++) { > - res = dom_in_list(prev_xml[i].uuid, cur_count, cur_xml); > - if (!res) > - async_ind(context, CS_DELETED, > - prev_xml[i], prefix, args); > - } > + if (cb_id == -1) { > + CU_DEBUG("Failed to register domain event watch for '%s'", > + args->classname) > + goto cb_out; > + } > > - for (i = 0; i< prev_count; i++) { > - res = dom_changed(prev_xml[i], cur_xml, cur_count); > - if (res) { > - async_ind(context, CS_MODIFIED, > - prev_xml[i], prefix, args); > + CBAttachThread(_BROKER, args->context); > > - } > - free_dom_xml(prev_xml[i]); > - } > + /* Get currently defined domains */ > + if (update_domain_list(conn, thread) != CMPI_RC_OK) > + goto end; > > - fail: > - if (failure) { > - wait_for_event(FAIL_WAIT_TIME); > - } else { > - free(prev_xml); > - prev_xml = cur_xml; > - prev_count = cur_count; > > - wait_for_event(WAIT_TIME); > + CU_DEBUG("Entering CSI event loop (%s)", prefix); > + while (thread->active_filters> 0) { > + if (virEventRunDefaultImpl()< 0) { > + virErrorPtr err = virGetLastError(); > + CU_DEBUG("Failed to run event loop: %s\n", > + err&& err->message ? err->message : "Unknown error"); > } > } > > CU_DEBUG("Exiting CSI event loop (%s)", prefix); > > - thread_id[platform] = 0; > + CBDetachThread(_BROKER, args->context); > + end: > + virConnectDomainEventDeregisterAny(conn, cb_id); > > - pthread_mutex_unlock(&lifecycle_mutex); > - stdi_free_ind_args(&args); > + cb_out: > + > + thread->id = 0; > + thread->active_filters = 0; > + > + if (thread->args != NULL) > + stdi_free_ind_args(&thread->args); > > conn_out: > virConnectClose(conn); > > init_out: > free(prefix); > + return (CMPI_THREAD_RETURN) 0; > +} > > - return NULL; > +static int platform_from_class(const char *cn) > +{ > + if (STARTS_WITH(cn, "Xen")) > + return CSI_XEN; > + else if (STARTS_WITH(cn, "KVM")) > + return CSI_KVM; > + else if (STARTS_WITH(cn, "LXC")) > + return CSI_LXC; > + else > + return -1; > } > > static CMPIStatus ActivateFilter(CMPIIndicationMI* mi, > @@ -622,17 +694,25 @@ static CMPIStatus ActivateFilter(CMPIIndicationMI* mi, > { > CMPIStatus s = {CMPI_RC_OK, NULL}; > struct std_indication_ctx *_ctx; > - struct ind_args *args; > + struct ind_args *args = NULL; > int platform; > + bool error = false; > + csi_thread_data_t *thread = NULL; > + static int events_registered = 0; > > CU_DEBUG("ActivateFilter for %s", CLASSNAME(op)); > > pthread_mutex_lock(&lifecycle_mutex); > > + if (events_registered == 0) { > + events_registered = 1; > + virEventRegisterDefaultImpl(); > + } > + > _ctx = (struct std_indication_ctx *)mi->hdl; > > if (CMIsNullObject(op)) { > - cu_statusf(_BROKER,&s, > + cu_statusf(_BROKER,&s, > CMPI_RC_ERR_FAILED, > "No ObjectPath given"); > goto out; > @@ -647,13 +727,17 @@ static CMPIStatus ActivateFilter(CMPIIndicationMI* mi, > goto out; > } > > - if (thread_id[platform] == 0) { > - args = malloc(sizeof(struct ind_args)); > + thread =&csi_thread_data[platform]; > + thread->active_filters += 1; > + > + if (thread->id == 0) { > + args = malloc(sizeof(*args)); > if (args == NULL) { > CU_DEBUG("Failed to allocate ind_args"); > cu_statusf(_BROKER,&s, > CMPI_RC_ERR_FAILED, > "Unable to allocate ind_args"); > + error = true; > goto out; > } > > @@ -663,7 +747,7 @@ static CMPIStatus ActivateFilter(CMPIIndicationMI* mi, > cu_statusf(_BROKER,&s, > CMPI_RC_ERR_FAILED, > "Unable to create thread context"); > - free(args); > + error = true; > goto out; > } > > @@ -671,15 +755,17 @@ static CMPIStatus ActivateFilter(CMPIIndicationMI* mi, > args->classname = strdup(CLASSNAME(op)); > args->_ctx = _ctx; > > - active_filters[platform] += 1; > - > - thread_id[platform] = _BROKER->xft->newThread(lifecycle_thread, > - args, > - 0); > - } else > - active_filters[platform] += 1; > + thread->args = args; > + thread->id = _BROKER->xft->newThread(lifecycle_thread, > + thread, 0); > + } > > out: > + if (error == true) { > + thread->active_filters -= 1; > + free(args); > + } > + > pthread_mutex_unlock(&lifecycle_mutex); > > return s; > @@ -705,11 +791,11 @@ static CMPIStatus DeActivateFilter(CMPIIndicationMI* mi, > goto out; > } > > + > pthread_mutex_lock(&lifecycle_mutex); > - active_filters[platform] -= 1; > + csi_thread_data[platform].active_filters -= 1; > pthread_mutex_unlock(&lifecycle_mutex); > > - pthread_cond_signal(&lifecycle_cond); > out: > return s; > } > @@ -736,13 +822,6 @@ static _EI_RTYPE DisableIndications(CMPIIndicationMI* mi, > _EI_RET(); > } > > -static CMPIStatus trigger_indication(const CMPIContext *context) > -{ > - CU_DEBUG("triggered"); > - pthread_cond_signal(&lifecycle_cond); > - return(CMPIStatus){CMPI_RC_OK, NULL}; > -} > - > DECLARE_FILTER(xen_created, "Xen_ComputerSystemCreatedIndication"); > DECLARE_FILTER(xen_deleted, "Xen_ComputerSystemDeletedIndication"); > DECLARE_FILTER(xen_modified, "Xen_ComputerSystemModifiedIndication"); > @@ -766,126 +845,7 @@ static struct std_ind_filter *filters[] = { > NULL, > }; > > -static CMPIInstance *get_prev_inst(const CMPIBroker *broker, > - const CMPIInstance *ind, > - CMPIStatus *s) > -{ > - CMPIData data; > - CMPIInstance *prev_inst = NULL; > - > - data = CMGetProperty(ind, "PreviousInstance", s); > - if (s->rc != CMPI_RC_OK || CMIsNullValue(data)) { > - cu_statusf(broker, s, > - CMPI_RC_ERR_NO_SUCH_PROPERTY, > - "Unable to get PreviousInstance of the indication"); > - goto out; > - } > - > - if (data.type != CMPI_instance) { > - cu_statusf(broker, s, > - CMPI_RC_ERR_TYPE_MISMATCH, > - "Indication SourceInstance is of unexpected type"); > - goto out; > - } > - > - prev_inst = data.value.inst; > - > - out: > - return prev_inst; > -} > - > -static CMPIStatus raise_indication(const CMPIBroker *broker, > - const CMPIContext *ctx, > - const CMPIObjectPath *ref, > - const CMPIInstance *ind) > -{ > - CMPIStatus s = {CMPI_RC_OK, NULL}; > - CMPIInstance *prev_inst; > - CMPIInstance *src_inst; > - CMPIObjectPath *_ref = NULL; > - struct std_indication_ctx *_ctx = NULL; > - struct ind_args *args = NULL; > - char *prefix = NULL; > - bool rc; > - > - if (!lifecycle_enabled) { > - cu_statusf(_BROKER,&s, > - CMPI_RC_ERR_FAILED, > - "CSI not enabled, skipping indication delivery"); > - goto out; > - } > - > - prev_inst = get_prev_inst(broker, ind,&s); > - if (s.rc != CMPI_RC_OK || CMIsNullObject(prev_inst)) > - goto out; > - > - _ref = CMGetObjectPath(prev_inst,&s); > - if (s.rc != CMPI_RC_OK) { > - cu_statusf(broker,&s, > - CMPI_RC_ERR_FAILED, > - "Unable to get a reference to the guest"); > - goto out; > - } > - > - /* FIXME: This is a Pegasus work around. Pegsus loses the namespace > - when an ObjectPath is pulled from an instance */ > - if (STREQ(NAMESPACE(_ref), "")) > - CMSetNameSpace(_ref, "root/virt"); > - > - s = get_domain_by_ref(broker, _ref,&src_inst); > - if (s.rc != CMPI_RC_OK || CMIsNullObject(src_inst)) > - goto out; > - > - _ctx = malloc(sizeof(struct std_indication_ctx)); > - if (_ctx == NULL) { > - cu_statusf(broker,&s, > - CMPI_RC_ERR_FAILED, > - "Unable to allocate indication context"); > - goto out; > - } > - > - _ctx->brkr = broker; > - _ctx->handler = NULL; > - _ctx->filters = filters; > - _ctx->enabled = lifecycle_enabled; > - > - args = malloc(sizeof(struct ind_args)); > - if (args == NULL) { > - cu_statusf(broker,&s, > - CMPI_RC_ERR_FAILED, > - "Unable to allocate ind_args"); > - goto out; > - } > - > - args->ns = strdup(NAMESPACE(_ref)); > - args->classname = strdup(CLASSNAME(_ref)); > - args->_ctx = _ctx; > - > - prefix = class_prefix_name(args->classname); > - > - rc = _do_indication(broker, ctx, prev_inst, src_inst, > - CS_MODIFIED, prefix, args); > - > - if (!rc) { > - cu_statusf(_BROKER,&s, > - CMPI_RC_ERR_FAILED, > - "Unable to generate indication"); > - } > - > - out: > - if (args != NULL) > - stdi_free_ind_args(&args); > - > - if (_ctx != NULL) > - free(_ctx); > - > - free(prefix); > - return s; > -} > - > static struct std_indication_handler csi = { > - .raise_fn = raise_indication, > - .trigger_fn = trigger_indication, > .activate_fn = ActivateFilter, > .deactivate_fn = DeActivateFilter, > .enable_fn = EnableIndications, > @@ -896,10 +856,10 @@ DEFAULT_IND_CLEANUP(); > DEFAULT_AF(); > DEFAULT_MP(); > > -STDI_IndicationMIStub(, > +STDI_IndicationMIStub(, > Virt_ComputerSystemIndicationProvider, > _BROKER, > - libvirt_cim_init(), > + libvirt_cim_init(), > &csi, > filters); > > diff --git a/src/Virt_ComputerSystemIndication.h b/src/Virt_ComputerSystemIndication.h > index 0f8f1b7..594c3ed 100644 > --- a/src/Virt_ComputerSystemIndication.h > +++ b/src/Virt_ComputerSystemIndication.h > @@ -24,11 +24,6 @@ > #include > #include > > -bool cs_lifecycle_indication(const CMPIBroker *broker, > - const CMPIContext *ctx, > - const CMPIObjectPath *newsystem, > - char *type); > - > void set_source_inst_props(const CMPIBroker *broker, > const CMPIContext *context, > const CMPIObjectPath *ref, > diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c > index 4d26429..46bc9b5 100644 > --- a/src/Virt_VirtualSystemManagementService.c > +++ b/src/Virt_VirtualSystemManagementService.c > @@ -1894,7 +1894,7 @@ static CMPIStatus raise_rasd_indication(const CMPIContext *context, > CMPIObjectPath *op = NULL; > int i; > > - CU_DEBUG("raise_rasd_indication"); > + CU_DEBUG("raise_rasd_indication %s", base_type); > > type = get_typed_class(CLASSNAME(ref), base_type); > > @@ -2105,22 +2105,6 @@ static CMPIInstance *create_system(const CMPIContext *context, > return inst; > } > > -static bool trigger_indication(const CMPIContext *context, > - const char *base_type, > - const CMPIObjectPath *ref) > -{ > - char *type; > - CMPIStatus s; > - > - type = get_typed_class(CLASSNAME(ref), base_type); > - > - s = stdi_trigger_indication(_BROKER, context, type, NAMESPACE(ref)); > - > - free(type); > - > - return s.rc == CMPI_RC_OK; > -} > - > static CMPIStatus define_system(CMPIMethodMI *self, > const CMPIContext *context, > const CMPIResult *results, > @@ -2156,9 +2140,6 @@ static CMPIStatus define_system(CMPIMethodMI *self, > CMAddArg(argsout, "ResultingSystem",&result, CMPI_ref); > } > > - trigger_indication(context, > - "ComputerSystemCreatedIndication", > - reference); > out: > if (s.rc == CMPI_RC_OK) > rc = CIM_SVPC_RETURN_COMPLETED; > @@ -2261,9 +2242,6 @@ error: > NULL, > reference, > &list); > - trigger_indication(context, > - "ComputerSystemDeletedIndication", > - reference); > } > > virDomainFree(dom); > @@ -2345,12 +2323,8 @@ static CMPIStatus update_system_settings(const CMPIContext *context, > connect_and_create(xml, ref,&s); > } > > - if (s.rc == CMPI_RC_OK) { > + if (s.rc == CMPI_RC_OK) > set_autostart(vssd, ref, dom); > - trigger_indication(context, > - "ComputerSystemModifiedIndication", > - ref); > - } > > out: > free(xml); -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From eblima at linux.vnet.ibm.com Wed Jan 4 18:51:01 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Wed, 4 Jan 2012 16:51:01 -0200 Subject: [Libvirt-cim] [PATCH] Remove compilation warnings Message-ID: <1325703061-12804-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" I am building libvirt-cim with gcc 4.6.3 in fedora 16 and got a bunch of new warnings. Most of them are about variables that are set but not used anywhere, but there is one possible access to unitialized variables in Virt_RASD.c which might result in unexpected behavior. xmlgen.c: In function 'system_xml': xmlgen.c:633:28: error: variable 'bl' set but not used [-Werror=unused-but-set-variable] xmlgen.c:642:28: error: variable 'bl_args' set but not used [-Werror=unused-but-set-variable] xmlgen.c: In function 'disk_pool_xml': xmlgen.c:1244:20: error: variable 'path' set but not used [-Werror=unused-but-set-variable] xmlgen.c: In function 'filter_to_xml': xmlgen.c:1474:15: error: variable 'msg' set but not used [-Werror=unused-but-set-variable] Virt_FilterEntry.c: In function 'enum_filter_rules': Virt_FilterEntry.c:576:30: error: variable 'class_type' set but not used [-Werror=unused-but-set-variable] Virt_RASD.c: In function 'rasd_from_vdev': Virt_RASD.c:406:27: error: 'pool' may be used uninitialized in this function [-Werror=uninitialized] Virt_RASD.c:330:27: note: 'pool' was declared here Virt_RASD.c:407:26: error: 'vol' may be used uninitialized in this function [-Werror=uninitialized] Virt_RASD.c:320:26: note: 'vol' was declared here Virt_VSMigrationService.c: In function 'clear_infstore_migration_flag': Virt_VSMigrationService.c:1185:15: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] Virt_VSMigrationService.c: In function 'migrate_do': Virt_VSMigrationService.c:1478:15: error: variable 'thread' set but not used [-Werror=unused-but-set-variable] Virt_Device.c: In function 'device_instances': Virt_Device.c:431:15: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] Virt_Device.c: In function 'proc_dev_list': Virt_Device.c:657:13: error: variable 'rc' set but not used [-Werror=unused-but-set-variable] Virt_Device.c: In function 'get_device_by_name': Virt_Device.c:769:21: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] Virt_Device.c:729:15: error: variable 'rc' set but not used [-Werror=unused-but-set-variable] Virt_VirtualSystemManagementService.c: In function 'input_rasd_to_vdev': Virt_VirtualSystemManagementService.c:1384:21: error: variable 'msg' set but not used [-Werror=unused-but-set-variable] Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/xmlgen.c | 34 ++++++------------------ src/Virt_Device.c | 39 +++++++++-------------------- src/Virt_FilterEntry.c | 11 ++------ src/Virt_RASD.c | 17 +++++++----- src/Virt_VSMigrationService.c | 6 +--- src/Virt_VirtualSystemManagementService.c | 5 +-- 6 files changed, 38 insertions(+), 74 deletions(-) diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index afd8c21..46712df 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -630,21 +630,17 @@ static char *system_xml(xmlNodePtr root, struct domain *domain) tmp = xmlNewChild(root, NULL, BAD_CAST "name", BAD_CAST domain->name); if (domain->bootloader) { - xmlNodePtr bl; - - bl = xmlNewChild(root, - NULL, - BAD_CAST "bootloader", - BAD_CAST domain->bootloader); + tmp = xmlNewChild(root, + NULL, + BAD_CAST "bootloader", + BAD_CAST domain->bootloader); } if (domain->bootloader_args) { - xmlNodePtr bl_args; - - bl_args = xmlNewChild(root, - NULL, - BAD_CAST "bootloader_args", - BAD_CAST domain->bootloader_args); + tmp = xmlNewChild(root, + NULL, + BAD_CAST "bootloader_args", + BAD_CAST domain->bootloader_args); } tmp = xmlNewChild(root, @@ -1241,7 +1237,6 @@ static const char *disk_pool_xml(xmlNodePtr root, xmlNodePtr disk = NULL; xmlNodePtr name = NULL; xmlNodePtr target = NULL; - xmlNodePtr path = NULL; const char *type = NULL; const char *msg = NULL; struct disk_pool *pool = &_pool->pool_info.disk; @@ -1271,7 +1266,7 @@ static const char *disk_pool_xml(xmlNodePtr root, if (target == NULL) goto out; - path = xmlNewChild(target, NULL, BAD_CAST "path", BAD_CAST pool->path); + xmlNewChild(target, NULL, BAD_CAST "path", BAD_CAST pool->path); if (target == NULL) goto out; @@ -1471,7 +1466,6 @@ char *res_to_xml(struct virt_pool_res *res) { char *filter_to_xml(struct acl_filter *filter) { - char *msg = XML_ERROR; char *xml = NULL; xmlNodePtr root = NULL; xmlNodePtr tmp = NULL; @@ -1504,17 +1498,7 @@ char *filter_to_xml(struct acl_filter *filter) goto out; } - /* TODO: Not yet supported - for (i = 0; i < filter->rule_ct; i++) { - msg = rule_to_xml(root, filter->rules[i]); - if (msg != NULL) - goto out; - } - */ - xml = tree_to_xml(root); - if (xml != NULL) - msg = NULL; /* no errors */ out: CU_DEBUG("Filter XML: %s", xml); diff --git a/src/Virt_Device.c b/src/Virt_Device.c index faa304d..fd11370 100644 --- a/src/Virt_Device.c +++ b/src/Virt_Device.c @@ -428,7 +428,6 @@ static bool device_instances(const CMPIBroker *broker, struct inst_list *list) { int i; - bool ret; uint64_t proc_count = 0; CMPIInstance *instance = NULL; @@ -475,11 +474,7 @@ static bool device_instances(const CMPIBroker *broker, } if (proc_count) { - ret = vcpu_instances(broker, - dom, - ns, - proc_count, - list); + vcpu_instances(broker, dom, ns, proc_count, list); } return true; @@ -654,16 +649,17 @@ static int proc_dev_list(uint64_t quantity, struct virt_device **list) { int i; - int rc; - *list = (struct virt_device *)calloc(quantity, sizeof(struct virt_device)); for (i = 0; i < quantity; i++) { char *dev_num; + int ret; - rc = asprintf(&dev_num, "%d", i); + ret = asprintf(&dev_num, "%d", i); + if (ret == -1) + CU_DEBUG("asprintf error %d" , ret); (*list)[i].id = strdup(dev_num); @@ -726,7 +722,6 @@ CMPIStatus get_device_by_name(const CMPIBroker *broker, virDomainPtr dom = NULL; struct virt_device *dev = NULL; struct inst_list tmp_list; - bool rc; inst_list_init(&tmp_list); @@ -766,24 +761,14 @@ CMPIStatus get_device_by_name(const CMPIBroker *broker, } if (type == CIM_RES_TYPE_PROC) { - int ret; int dev_id_num; - - ret = sscanf(dev->id, "%d", &dev_id_num); + sscanf(dev->id, "%d", &dev_id_num); - rc = vcpu_inst(broker, - dom, - NAMESPACE(reference), - dev_id_num, - &tmp_list); + vcpu_inst(broker, dom, NAMESPACE(reference), + dev_id_num, &tmp_list); } else { - - rc = device_instances(broker, - dev, - 1, - dom, - NAMESPACE(reference), - &tmp_list); + device_instances(broker, dev, 1, dom, + NAMESPACE(reference), &tmp_list); } cleanup_virt_devices(&dev, 1); @@ -799,8 +784,8 @@ CMPIStatus get_device_by_name(const CMPIBroker *broker, inst_list_free(&tmp_list); virConnectClose(conn); - return s; -} + return s; +} CMPIStatus get_device_by_ref(const CMPIBroker *broker, const CMPIObjectPath *reference, diff --git a/src/Virt_FilterEntry.c b/src/Virt_FilterEntry.c index acc3d61..16b211e 100644 --- a/src/Virt_FilterEntry.c +++ b/src/Virt_FilterEntry.c @@ -573,17 +573,12 @@ CMPIStatus enum_filter_rules( struct acl_filter *filters = NULL; int i, j, count = 0; CMPIStatus s = {CMPI_RC_OK, NULL}; - enum {NONE, MAC, IP} class_type = NONE; CU_DEBUG("Reference = %s", REF2STR(reference)); - if (STREQC(CLASSNAME(reference), "KVM_Hdr8021Filter")) { - class_type = MAC; - } else if (STREQC(CLASSNAME(reference), "KVM_IPHeadersFilter")) { - class_type = IP; - } else if (STREQC(CLASSNAME(reference), "KVM_FilterEntry")) { - class_type = NONE; - } else { + if (!STREQC(CLASSNAME(reference), "KVM_Hdr8021Filter") && + !STREQC(CLASSNAME(reference), "KVM_IPHeadersFilter") && + !STREQC(CLASSNAME(reference), "KVM_FilterEntry")) { cu_statusf(broker, &s, CMPI_RC_ERR_FAILED, "Unrecognized class type"); diff --git a/src/Virt_RASD.c b/src/Virt_RASD.c index 4ac2f93..4939f7b 100644 --- a/src/Virt_RASD.c +++ b/src/Virt_RASD.c @@ -289,6 +289,11 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, uint16_t type; CMPIStatus s = {CMPI_RC_OK, NULL}; char *poolid = NULL; + virConnectPtr conn = NULL; + virStorageVolPtr vol = NULL; + virStoragePoolPtr pool = NULL; + const char *pool_name = NULL; + int ret = -1; get_vol_size(broker, ref, dev->dev.disk.source, &cap); @@ -308,7 +313,7 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, (CMPIValue *)dev->dev.disk.source, CMPI_chars); - virConnectPtr conn = connect_by_classname(broker, CLASSNAME(ref), &s); + conn = connect_by_classname(broker, CLASSNAME(ref), &s); if (conn == NULL) { virt_set_status(broker, &s, CMPI_RC_ERR_NOT_FOUND, @@ -317,8 +322,7 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, goto cont; } - virStorageVolPtr vol = virStorageVolLookupByPath(conn, - dev->dev.disk.source); + vol = virStorageVolLookupByPath(conn, dev->dev.disk.source); if (vol == NULL) { virt_set_status(broker, &s, CMPI_RC_ERR_NOT_FOUND, @@ -327,7 +331,7 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, goto cont; } - virStoragePoolPtr pool = virStoragePoolLookupByVolume(vol); + pool = virStoragePoolLookupByVolume(vol); if (pool == NULL) { virt_set_status(broker, &s, CMPI_RC_ERR_NOT_FOUND, @@ -336,7 +340,7 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, goto cont; } - const char *pool_name = virStoragePoolGetName(pool); + pool_name = virStoragePoolGetName(pool); if (pool_name == NULL) { virt_set_status(broker, &s, CMPI_RC_ERR_NOT_FOUND, @@ -345,8 +349,7 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, goto cont; } - int ret = asprintf(&poolid, "DiskPool/%s", pool_name); - + ret = asprintf(&poolid, "DiskPool/%s", pool_name); if (ret == -1) { CU_DEBUG("Failed to get disk poolid"); goto cont; diff --git a/src/Virt_VSMigrationService.c b/src/Virt_VSMigrationService.c index 4f48a68..d393787 100644 --- a/src/Virt_VSMigrationService.c +++ b/src/Virt_VSMigrationService.c @@ -1182,7 +1182,6 @@ static CMPIStatus ensure_dom_offline(virDomainPtr dom) static void clear_infstore_migration_flag(virDomainPtr dom) { struct infostore_ctx *infp; - bool ret = false; infp = infostore_open(dom); if (infp == NULL) { @@ -1191,7 +1190,7 @@ static void clear_infstore_migration_flag(virDomainPtr dom) return; } - ret = infostore_set_bool(infp, "migrating", false); + infostore_set_bool(infp, "migrating", false); CU_DEBUG("Clearing infostore migrating flag"); infostore_close(infp); @@ -1475,7 +1474,6 @@ static CMPIStatus migrate_do(const CMPIObjectPath *ref, CMPIStatus s; CMPIObjectPath *job_op; struct migration_job *job; - CMPI_THREAD_TYPE thread; uint32_t retcode = 1; CMPIInstance *ind = NULL; CMPIInstance *inst = NULL; @@ -1517,7 +1515,7 @@ static CMPIStatus migrate_do(const CMPIObjectPath *ref, if (!rc) CU_DEBUG("Failed to raise indication"); - thread = _BROKER->xft->newThread((void*)migration_thread, job, 0); + _BROKER->xft->newThread((void*)migration_thread, job, 0); retcode = CIM_SVPC_RETURN_JOB_STARTED; diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c index 5229f56..f8c5f24 100644 --- a/src/Virt_VirtualSystemManagementService.c +++ b/src/Virt_VirtualSystemManagementService.c @@ -1381,10 +1381,9 @@ static const char *input_rasd_to_vdev(CMPIInstance *inst, struct virt_device *dev) { const char *val; - const char *msg; if (cu_get_str_prop(inst, "ResourceSubType", &val) != CMPI_RC_OK) { - msg = "InputRASD ResourceSubType field not valid"; + CU_DEBUG("InputRASD ResourceSubType field not valid"); goto out; } dev->dev.input.type = strdup(val); @@ -1395,7 +1394,7 @@ static const char *input_rasd_to_vdev(CMPIInstance *inst, else if (STREQC(dev->dev.input.type, "tablet")) dev->dev.input.bus = strdup("usb"); else { - msg = "Invalid value for ResourceSubType in InputRASD"; + CU_DEBUG("Invalid value for ResourceSubType in InputRASD"); goto out; } } else -- 1.7.7.5 From snmishra at us.ibm.com Thu Jan 5 18:26:05 2012 From: snmishra at us.ibm.com (Sharad Mishra) Date: Thu, 5 Jan 2012 10:26:05 -0800 Subject: [Libvirt-cim] [PATCH] Remove compilation warnings In-Reply-To: <1325703061-12804-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1325703061-12804-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: Looks good except for one minor change - Sharad Mishra Open Virtualization Linux Technology Center IBM libvirt-cim-bounces at redhat.com wrote on 01/04/2012 10:51:01 AM: > "Eduardo Lima (Etrunko)" > Sent by: libvirt-cim-bounces at redhat.com > > 01/04/2012 10:51 AM > > Please respond to > List for discussion and development of libvirt CIM > > To > > libvirt-cim at redhat.com > > cc > > "Eduardo Lima \(Etrunko\)" > > Subject > > [Libvirt-cim] [PATCH] Remove compilation warnings > > From: "Eduardo Lima (Etrunko)" > > I am building libvirt-cim with gcc 4.6.3 in fedora 16 and got a bunch of new > warnings. Most of them are about variables that are set but not usedanywhere, > but there is one possible access to unitialized variables in Virt_RASD.c which > might result in unexpected behavior. > > xmlgen.c: In function 'system_xml': > xmlgen.c:633:28: error: variable 'bl' set but not used [- > Werror=unused-but-set-variable] > xmlgen.c:642:28: error: variable 'bl_args' set but not used [- > Werror=unused-but-set-variable] > xmlgen.c: In function 'disk_pool_xml': > xmlgen.c:1244:20: error: variable 'path' set but not used [- > Werror=unused-but-set-variable] > xmlgen.c: In function 'filter_to_xml': > xmlgen.c:1474:15: error: variable 'msg' set but not used [- > Werror=unused-but-set-variable] > > Virt_FilterEntry.c: In function 'enum_filter_rules': > Virt_FilterEntry.c:576:30: error: variable 'class_type' set but not > used [-Werror=unused-but-set-variable] > > Virt_RASD.c: In function 'rasd_from_vdev': > Virt_RASD.c:406:27: error: 'pool' may be used uninitialized in this > function [-Werror=uninitialized] > Virt_RASD.c:330:27: note: 'pool' was declared here > Virt_RASD.c:407:26: error: 'vol' may be used uninitialized in this > function [-Werror=uninitialized] > Virt_RASD.c:320:26: note: 'vol' was declared here > > Virt_VSMigrationService.c: In function 'clear_infstore_migration_flag': > Virt_VSMigrationService.c:1185:15: error: variable 'ret' set but not > used [-Werror=unused-but-set-variable] > Virt_VSMigrationService.c: In function 'migrate_do': > Virt_VSMigrationService.c:1478:15: error: variable 'thread' set but > not used [-Werror=unused-but-set-variable] > > Virt_Device.c: In function 'device_instances': > Virt_Device.c:431:15: error: variable 'ret' set but not used [- > Werror=unused-but-set-variable] > Virt_Device.c: In function 'proc_dev_list': > Virt_Device.c:657:13: error: variable 'rc' set but not used [- > Werror=unused-but-set-variable] > Virt_Device.c: In function 'get_device_by_name': > Virt_Device.c:769:21: error: variable 'ret' set but not used [- > Werror=unused-but-set-variable] > Virt_Device.c:729:15: error: variable 'rc' set but not used [- > Werror=unused-but-set-variable] > > Virt_VirtualSystemManagementService.c: In function 'input_rasd_to_vdev': > Virt_VirtualSystemManagementService.c:1384:21: error: variable 'msg' > set but not used [-Werror=unused-but-set-variable] > > Signed-off-by: Eduardo Lima (Etrunko) > --- > libxkutil/xmlgen.c | 34 +++++ +------------------ > src/Virt_Device.c | 39 ++++++++ > +-------------------- > src/Virt_FilterEntry.c | 11 ++------ > src/Virt_RASD.c | 17 +++++++----- > src/Virt_VSMigrationService.c | 6 +--- > src/Virt_VirtualSystemManagementService.c | 5 +-- > 6 files changed, 38 insertions(+), 74 deletions(-) > > diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c > index afd8c21..46712df 100644 > --- a/libxkutil/xmlgen.c > +++ b/libxkutil/xmlgen.c > @@ -630,21 +630,17 @@ static char *system_xml(xmlNodePtr root, > struct domain *domain) > tmp = xmlNewChild(root, NULL, BAD_CAST "name", BAD_CAST > domain->name); > > if (domain->bootloader) { > - xmlNodePtr bl; > - > - bl = xmlNewChild(root, > - NULL, > - BAD_CAST "bootloader", > - BAD_CAST domain->bootloader); > + tmp = xmlNewChild(root, > + NULL, > + BAD_CAST "bootloader", > + BAD_CAST domain->bootloader); > } > > if (domain->bootloader_args) { > - xmlNodePtr bl_args; > - > - bl_args = xmlNewChild(root, > - NULL, > - BAD_CAST "bootloader_args", > - BAD_CAST domain->bootloader_args); > + tmp = xmlNewChild(root, > + NULL, > + BAD_CAST "bootloader_args", > + BAD_CAST domain->bootloader_args); > } > > tmp = xmlNewChild(root, > @@ -1241,7 +1237,6 @@ static const char *disk_pool_xml(xmlNodePtr root, > xmlNodePtr disk = NULL; > xmlNodePtr name = NULL; > xmlNodePtr target = NULL; > - xmlNodePtr path = NULL; > const char *type = NULL; > const char *msg = NULL; > struct disk_pool *pool = &_pool->pool_info.disk; > @@ -1271,7 +1266,7 @@ static const char *disk_pool_xml(xmlNodePtr root, > if (target == NULL) > goto out; > > - path = xmlNewChild(target, NULL, BAD_CAST "path", BAD_CAST > pool->path); > + xmlNewChild(target, NULL, BAD_CAST "path", BAD_CAST pool->path); > if (target == NULL) > goto out; 'path' should be kept and the check should change to - if (path == NULL) goto out; > > @@ -1471,7 +1466,6 @@ char *res_to_xml(struct virt_pool_res *res) { > > char *filter_to_xml(struct acl_filter *filter) > { > - char *msg = XML_ERROR; > char *xml = NULL; > xmlNodePtr root = NULL; > xmlNodePtr tmp = NULL; > @@ -1504,17 +1498,7 @@ char *filter_to_xml(struct acl_filter *filter) > goto out; > } > > - /* TODO: Not yet supported > - for (i = 0; i < filter->rule_ct; i++) { > - msg = rule_to_xml(root, filter->rules[i]); > - if (msg != NULL) > - goto out; > - } > - */ > - > xml = tree_to_xml(root); > - if (xml != NULL) > - msg = NULL; /* no errors */ > > out: > CU_DEBUG("Filter XML: %s", xml); > diff --git a/src/Virt_Device.c b/src/Virt_Device.c > index faa304d..fd11370 100644 > --- a/src/Virt_Device.c > +++ b/src/Virt_Device.c > @@ -428,7 +428,6 @@ static bool device_instances(const CMPIBroker *broker, > struct inst_list *list) > { > int i; > - bool ret; > uint64_t proc_count = 0; > CMPIInstance *instance = NULL; > > @@ -475,11 +474,7 @@ static bool device_instances(const CMPIBroker *broker, > } > > if (proc_count) { > - ret = vcpu_instances(broker, > - dom, > - ns, > - proc_count, > - list); > + vcpu_instances(broker, dom, ns, proc_count, list); > } > > return true; > @@ -654,16 +649,17 @@ static int proc_dev_list(uint64_t quantity, > struct virt_device **list) > { > int i; > - int rc; > - > > *list = (struct virt_device *)calloc(quantity, > sizeof(struct virt_device)); > > for (i = 0; i < quantity; i++) { > char *dev_num; > + int ret; > > - rc = asprintf(&dev_num, "%d", i); > + ret = asprintf(&dev_num, "%d", i); > + if (ret == -1) > + CU_DEBUG("asprintf error %d" , ret); > > (*list)[i].id = strdup(dev_num); > > @@ -726,7 +722,6 @@ CMPIStatus get_device_by_name(const CMPIBroker *broker, > virDomainPtr dom = NULL; > struct virt_device *dev = NULL; > struct inst_list tmp_list; > - bool rc; > > inst_list_init(&tmp_list); > > @@ -766,24 +761,14 @@ CMPIStatus get_device_by_name(const CMPIBroker *broker, > } > > if (type == CIM_RES_TYPE_PROC) { > - int ret; > int dev_id_num; > - > - ret = sscanf(dev->id, "%d", &dev_id_num); > + sscanf(dev->id, "%d", &dev_id_num); > > - rc = vcpu_inst(broker, > - dom, > - NAMESPACE(reference), > - dev_id_num, > - &tmp_list); > + vcpu_inst(broker, dom, NAMESPACE(reference), > + dev_id_num, &tmp_list); > } else { > - > - rc = device_instances(broker, > - dev, > - 1, > - dom, > - NAMESPACE(reference), > - &tmp_list); > + device_instances(broker, dev, 1, dom, > + NAMESPACE(reference), &tmp_list); > } > > cleanup_virt_devices(&dev, 1); > @@ -799,8 +784,8 @@ CMPIStatus get_device_by_name(const CMPIBroker *broker, > inst_list_free(&tmp_list); > virConnectClose(conn); > > - return s; > -} > + return s; > +} > > CMPIStatus get_device_by_ref(const CMPIBroker *broker, > const CMPIObjectPath *reference, > diff --git a/src/Virt_FilterEntry.c b/src/Virt_FilterEntry.c > index acc3d61..16b211e 100644 > --- a/src/Virt_FilterEntry.c > +++ b/src/Virt_FilterEntry.c > @@ -573,17 +573,12 @@ CMPIStatus enum_filter_rules( > struct acl_filter *filters = NULL; > int i, j, count = 0; > CMPIStatus s = {CMPI_RC_OK, NULL}; > - enum {NONE, MAC, IP} class_type = NONE; > > CU_DEBUG("Reference = %s", REF2STR(reference)); > > - if (STREQC(CLASSNAME(reference), "KVM_Hdr8021Filter")) { > - class_type = MAC; > - } else if (STREQC(CLASSNAME(reference), "KVM_IPHeadersFilter")) { > - class_type = IP; > - } else if (STREQC(CLASSNAME(reference), "KVM_FilterEntry")) { > - class_type = NONE; > - } else { > + if (!STREQC(CLASSNAME(reference), "KVM_Hdr8021Filter") && > + !STREQC(CLASSNAME(reference), "KVM_IPHeadersFilter") && > + !STREQC(CLASSNAME(reference), "KVM_FilterEntry")) { > cu_statusf(broker, &s, > CMPI_RC_ERR_FAILED, > "Unrecognized class type"); > diff --git a/src/Virt_RASD.c b/src/Virt_RASD.c > index 4ac2f93..4939f7b 100644 > --- a/src/Virt_RASD.c > +++ b/src/Virt_RASD.c > @@ -289,6 +289,11 @@ static CMPIStatus set_disk_rasd_params(const > CMPIBroker *broker, > uint16_t type; > CMPIStatus s = {CMPI_RC_OK, NULL}; > char *poolid = NULL; > + virConnectPtr conn = NULL; > + virStorageVolPtr vol = NULL; > + virStoragePoolPtr pool = NULL; > + const char *pool_name = NULL; > + int ret = -1; > > get_vol_size(broker, ref, dev->dev.disk.source, &cap); > > @@ -308,7 +313,7 @@ static CMPIStatus set_disk_rasd_params(const > CMPIBroker *broker, > (CMPIValue *)dev->dev.disk.source, > CMPI_chars); > > - virConnectPtr conn = connect_by_classname(broker, CLASSNAME > (ref), &s); > + conn = connect_by_classname(broker, CLASSNAME(ref), &s); > if (conn == NULL) { > virt_set_status(broker, &s, > CMPI_RC_ERR_NOT_FOUND, > @@ -317,8 +322,7 @@ static CMPIStatus set_disk_rasd_params(const > CMPIBroker *broker, > goto cont; > } > > - virStorageVolPtr vol = virStorageVolLookupByPath(conn, > - > dev->dev.disk.source); > + vol = virStorageVolLookupByPath(conn, dev->dev.disk.source); > if (vol == NULL) { > virt_set_status(broker, &s, > CMPI_RC_ERR_NOT_FOUND, > @@ -327,7 +331,7 @@ static CMPIStatus set_disk_rasd_params(const > CMPIBroker *broker, > goto cont; > } > > - virStoragePoolPtr pool = virStoragePoolLookupByVolume(vol); > + pool = virStoragePoolLookupByVolume(vol); > if (pool == NULL) { > virt_set_status(broker, &s, > CMPI_RC_ERR_NOT_FOUND, > @@ -336,7 +340,7 @@ static CMPIStatus set_disk_rasd_params(const > CMPIBroker *broker, > goto cont; > } > > - const char *pool_name = virStoragePoolGetName(pool); > + pool_name = virStoragePoolGetName(pool); > if (pool_name == NULL) { > virt_set_status(broker, &s, > CMPI_RC_ERR_NOT_FOUND, > @@ -345,8 +349,7 @@ static CMPIStatus set_disk_rasd_params(const > CMPIBroker *broker, > goto cont; > } > > - int ret = asprintf(&poolid, "DiskPool/%s", pool_name); > - > + ret = asprintf(&poolid, "DiskPool/%s", pool_name); > if (ret == -1) { > CU_DEBUG("Failed to get disk poolid"); > goto cont; > diff --git a/src/Virt_VSMigrationService.c b/src/Virt_VSMigrationService.c > index 4f48a68..d393787 100644 > --- a/src/Virt_VSMigrationService.c > +++ b/src/Virt_VSMigrationService.c > @@ -1182,7 +1182,6 @@ static CMPIStatus ensure_dom_offline(virDomainPtr dom) > static void clear_infstore_migration_flag(virDomainPtr dom) > { > struct infostore_ctx *infp; > - bool ret = false; > > infp = infostore_open(dom); > if (infp == NULL) { > @@ -1191,7 +1190,7 @@ static void clear_infstore_migration_flag > (virDomainPtr dom) > return; > } > > - ret = infostore_set_bool(infp, "migrating", false); > + infostore_set_bool(infp, "migrating", false); > CU_DEBUG("Clearing infostore migrating flag"); > > infostore_close(infp); > @@ -1475,7 +1474,6 @@ static CMPIStatus migrate_do(const CMPIObjectPath *ref, > CMPIStatus s; > CMPIObjectPath *job_op; > struct migration_job *job; > - CMPI_THREAD_TYPE thread; > uint32_t retcode = 1; > CMPIInstance *ind = NULL; > CMPIInstance *inst = NULL; > @@ -1517,7 +1515,7 @@ static CMPIStatus migrate_do(const CMPIObjectPath *ref, > if (!rc) > CU_DEBUG("Failed to raise indication"); > > - thread = _BROKER->xft->newThread((void*)migration_thread, job, 0); > + _BROKER->xft->newThread((void*)migration_thread, job, 0); > > retcode = CIM_SVPC_RETURN_JOB_STARTED; > > diff --git a/src/Virt_VirtualSystemManagementService.c b/src/ > Virt_VirtualSystemManagementService.c > index 5229f56..f8c5f24 100644 > --- a/src/Virt_VirtualSystemManagementService.c > +++ b/src/Virt_VirtualSystemManagementService.c > @@ -1381,10 +1381,9 @@ static const char *input_rasd_to_vdev > (CMPIInstance *inst, > struct virt_device *dev) > { > const char *val; > - const char *msg; > > if (cu_get_str_prop(inst, "ResourceSubType", &val) != CMPI_RC_OK) { > - msg = "InputRASD ResourceSubType field not valid"; > + CU_DEBUG("InputRASD ResourceSubType field not valid"); > goto out; > } > dev->dev.input.type = strdup(val); > @@ -1395,7 +1394,7 @@ static const char *input_rasd_to_vdev > (CMPIInstance *inst, > else if (STREQC(dev->dev.input.type, "tablet")) > dev->dev.input.bus = strdup("usb"); > else { > - msg = "Invalid value for ResourceSubType in > InputRASD"; > + CU_DEBUG("Invalid value for ResourceSubType > in InputRASD"); > goto out; > } > } else > -- > 1.7.7.5 > > _______________________________________________ > Libvirt-cim mailing list > Libvirt-cim at redhat.com > https://www.redhat.com/mailman/listinfo/libvirt-cim > From eblima at linux.vnet.ibm.com Tue Jan 10 17:46:00 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 10 Jan 2012 15:46:00 -0200 Subject: [Libvirt-cim] [PATCH] Remove compilation warnings In-Reply-To: References: <1325703061-12804-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F0C7958.8080000@linux.vnet.ibm.com> On 01/05/2012 04:26 PM, Sharad Mishra wrote: > Looks good except for one minor change - > [snip] >> @@ -1241,7 +1237,6 @@ static const char *disk_pool_xml(xmlNodePtr root, >> xmlNodePtr disk = NULL; >> xmlNodePtr name = NULL; >> xmlNodePtr target = NULL; >> - xmlNodePtr path = NULL; >> const char *type = NULL; >> const char *msg = NULL; >> struct disk_pool *pool = &_pool->pool_info.disk; >> @@ -1271,7 +1266,7 @@ static const char *disk_pool_xml(xmlNodePtr root, >> if (target == NULL) >> goto out; >> >> - path = xmlNewChild(target, NULL, BAD_CAST "path", BAD_CAST >> pool->path); >> + xmlNewChild(target, NULL, BAD_CAST "path", BAD_CAST pool->path); >> if (target == NULL) >> goto out; > > > 'path' should be kept and the check should change to - > > if (path == NULL) > goto out; > Yes, indeed. Good catch, thanks. New Patch on the way. -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Tue Jan 10 17:47:42 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 10 Jan 2012 15:47:42 -0200 Subject: [Libvirt-cim] [PATCHv2] Remove compilation warnings Message-ID: <1326217662-8281-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" I am building libvirt-cim with gcc 4.6.3 in fedora 16 and got a bunch of new warnings. Most of them are about variables that are set but not used anywhere, but there is one possible access to unitialized variables in Virt_RASD.c which might result in unexpected behavior. xmlgen.c: In function 'system_xml': xmlgen.c:633:28: error: variable 'bl' set but not used [-Werror=unused-but-set-variable] xmlgen.c:642:28: error: variable 'bl_args' set but not used [-Werror=unused-but-set-variable] xmlgen.c: In function 'disk_pool_xml': xmlgen.c:1244:20: error: variable 'path' set but not used [-Werror=unused-but-set-variable] xmlgen.c: In function 'filter_to_xml': xmlgen.c:1474:15: error: variable 'msg' set but not used [-Werror=unused-but-set-variable] Virt_FilterEntry.c: In function 'enum_filter_rules': Virt_FilterEntry.c:576:30: error: variable 'class_type' set but not used [-Werror=unused-but-set-variable] Virt_RASD.c: In function 'rasd_from_vdev': Virt_RASD.c:406:27: error: 'pool' may be used uninitialized in this function [-Werror=uninitialized] Virt_RASD.c:330:27: note: 'pool' was declared here Virt_RASD.c:407:26: error: 'vol' may be used uninitialized in this function [-Werror=uninitialized] Virt_RASD.c:320:26: note: 'vol' was declared here Virt_VSMigrationService.c: In function 'clear_infstore_migration_flag': Virt_VSMigrationService.c:1185:15: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] Virt_VSMigrationService.c: In function 'migrate_do': Virt_VSMigrationService.c:1478:15: error: variable 'thread' set but not used [-Werror=unused-but-set-variable] Virt_Device.c: In function 'device_instances': Virt_Device.c:431:15: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] Virt_Device.c: In function 'proc_dev_list': Virt_Device.c:657:13: error: variable 'rc' set but not used [-Werror=unused-but-set-variable] Virt_Device.c: In function 'get_device_by_name': Virt_Device.c:769:21: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] Virt_Device.c:729:15: error: variable 'rc' set but not used [-Werror=unused-but-set-variable] Virt_VirtualSystemManagementService.c: In function 'input_rasd_to_vdev': Virt_VirtualSystemManagementService.c:1384:21: error: variable 'msg' set but not used [-Werror=unused-but-set-variable] Changes since v1: - xmlgen.c: Keep 'path' variable and fix value check. Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/xmlgen.c | 33 ++++++----------------- src/Virt_Device.c | 39 +++++++++-------------------- src/Virt_FilterEntry.c | 11 ++------ src/Virt_RASD.c | 17 +++++++----- src/Virt_VSMigrationService.c | 6 +--- src/Virt_VirtualSystemManagementService.c | 5 +-- 6 files changed, 38 insertions(+), 73 deletions(-) diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index afd8c21..d73ffd0 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -630,21 +630,17 @@ static char *system_xml(xmlNodePtr root, struct domain *domain) tmp = xmlNewChild(root, NULL, BAD_CAST "name", BAD_CAST domain->name); if (domain->bootloader) { - xmlNodePtr bl; - - bl = xmlNewChild(root, - NULL, - BAD_CAST "bootloader", - BAD_CAST domain->bootloader); + tmp = xmlNewChild(root, + NULL, + BAD_CAST "bootloader", + BAD_CAST domain->bootloader); } if (domain->bootloader_args) { - xmlNodePtr bl_args; - - bl_args = xmlNewChild(root, - NULL, - BAD_CAST "bootloader_args", - BAD_CAST domain->bootloader_args); + tmp = xmlNewChild(root, + NULL, + BAD_CAST "bootloader_args", + BAD_CAST domain->bootloader_args); } tmp = xmlNewChild(root, @@ -1272,7 +1268,7 @@ static const char *disk_pool_xml(xmlNodePtr root, goto out; path = xmlNewChild(target, NULL, BAD_CAST "path", BAD_CAST pool->path); - if (target == NULL) + if (path == NULL) goto out; return NULL; @@ -1471,7 +1467,6 @@ char *res_to_xml(struct virt_pool_res *res) { char *filter_to_xml(struct acl_filter *filter) { - char *msg = XML_ERROR; char *xml = NULL; xmlNodePtr root = NULL; xmlNodePtr tmp = NULL; @@ -1504,17 +1499,7 @@ char *filter_to_xml(struct acl_filter *filter) goto out; } - /* TODO: Not yet supported - for (i = 0; i < filter->rule_ct; i++) { - msg = rule_to_xml(root, filter->rules[i]); - if (msg != NULL) - goto out; - } - */ - xml = tree_to_xml(root); - if (xml != NULL) - msg = NULL; /* no errors */ out: CU_DEBUG("Filter XML: %s", xml); diff --git a/src/Virt_Device.c b/src/Virt_Device.c index faa304d..fd11370 100644 --- a/src/Virt_Device.c +++ b/src/Virt_Device.c @@ -428,7 +428,6 @@ static bool device_instances(const CMPIBroker *broker, struct inst_list *list) { int i; - bool ret; uint64_t proc_count = 0; CMPIInstance *instance = NULL; @@ -475,11 +474,7 @@ static bool device_instances(const CMPIBroker *broker, } if (proc_count) { - ret = vcpu_instances(broker, - dom, - ns, - proc_count, - list); + vcpu_instances(broker, dom, ns, proc_count, list); } return true; @@ -654,16 +649,17 @@ static int proc_dev_list(uint64_t quantity, struct virt_device **list) { int i; - int rc; - *list = (struct virt_device *)calloc(quantity, sizeof(struct virt_device)); for (i = 0; i < quantity; i++) { char *dev_num; + int ret; - rc = asprintf(&dev_num, "%d", i); + ret = asprintf(&dev_num, "%d", i); + if (ret == -1) + CU_DEBUG("asprintf error %d" , ret); (*list)[i].id = strdup(dev_num); @@ -726,7 +722,6 @@ CMPIStatus get_device_by_name(const CMPIBroker *broker, virDomainPtr dom = NULL; struct virt_device *dev = NULL; struct inst_list tmp_list; - bool rc; inst_list_init(&tmp_list); @@ -766,24 +761,14 @@ CMPIStatus get_device_by_name(const CMPIBroker *broker, } if (type == CIM_RES_TYPE_PROC) { - int ret; int dev_id_num; - - ret = sscanf(dev->id, "%d", &dev_id_num); + sscanf(dev->id, "%d", &dev_id_num); - rc = vcpu_inst(broker, - dom, - NAMESPACE(reference), - dev_id_num, - &tmp_list); + vcpu_inst(broker, dom, NAMESPACE(reference), + dev_id_num, &tmp_list); } else { - - rc = device_instances(broker, - dev, - 1, - dom, - NAMESPACE(reference), - &tmp_list); + device_instances(broker, dev, 1, dom, + NAMESPACE(reference), &tmp_list); } cleanup_virt_devices(&dev, 1); @@ -799,8 +784,8 @@ CMPIStatus get_device_by_name(const CMPIBroker *broker, inst_list_free(&tmp_list); virConnectClose(conn); - return s; -} + return s; +} CMPIStatus get_device_by_ref(const CMPIBroker *broker, const CMPIObjectPath *reference, diff --git a/src/Virt_FilterEntry.c b/src/Virt_FilterEntry.c index acc3d61..16b211e 100644 --- a/src/Virt_FilterEntry.c +++ b/src/Virt_FilterEntry.c @@ -573,17 +573,12 @@ CMPIStatus enum_filter_rules( struct acl_filter *filters = NULL; int i, j, count = 0; CMPIStatus s = {CMPI_RC_OK, NULL}; - enum {NONE, MAC, IP} class_type = NONE; CU_DEBUG("Reference = %s", REF2STR(reference)); - if (STREQC(CLASSNAME(reference), "KVM_Hdr8021Filter")) { - class_type = MAC; - } else if (STREQC(CLASSNAME(reference), "KVM_IPHeadersFilter")) { - class_type = IP; - } else if (STREQC(CLASSNAME(reference), "KVM_FilterEntry")) { - class_type = NONE; - } else { + if (!STREQC(CLASSNAME(reference), "KVM_Hdr8021Filter") && + !STREQC(CLASSNAME(reference), "KVM_IPHeadersFilter") && + !STREQC(CLASSNAME(reference), "KVM_FilterEntry")) { cu_statusf(broker, &s, CMPI_RC_ERR_FAILED, "Unrecognized class type"); diff --git a/src/Virt_RASD.c b/src/Virt_RASD.c index 4ac2f93..4939f7b 100644 --- a/src/Virt_RASD.c +++ b/src/Virt_RASD.c @@ -289,6 +289,11 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, uint16_t type; CMPIStatus s = {CMPI_RC_OK, NULL}; char *poolid = NULL; + virConnectPtr conn = NULL; + virStorageVolPtr vol = NULL; + virStoragePoolPtr pool = NULL; + const char *pool_name = NULL; + int ret = -1; get_vol_size(broker, ref, dev->dev.disk.source, &cap); @@ -308,7 +313,7 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, (CMPIValue *)dev->dev.disk.source, CMPI_chars); - virConnectPtr conn = connect_by_classname(broker, CLASSNAME(ref), &s); + conn = connect_by_classname(broker, CLASSNAME(ref), &s); if (conn == NULL) { virt_set_status(broker, &s, CMPI_RC_ERR_NOT_FOUND, @@ -317,8 +322,7 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, goto cont; } - virStorageVolPtr vol = virStorageVolLookupByPath(conn, - dev->dev.disk.source); + vol = virStorageVolLookupByPath(conn, dev->dev.disk.source); if (vol == NULL) { virt_set_status(broker, &s, CMPI_RC_ERR_NOT_FOUND, @@ -327,7 +331,7 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, goto cont; } - virStoragePoolPtr pool = virStoragePoolLookupByVolume(vol); + pool = virStoragePoolLookupByVolume(vol); if (pool == NULL) { virt_set_status(broker, &s, CMPI_RC_ERR_NOT_FOUND, @@ -336,7 +340,7 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, goto cont; } - const char *pool_name = virStoragePoolGetName(pool); + pool_name = virStoragePoolGetName(pool); if (pool_name == NULL) { virt_set_status(broker, &s, CMPI_RC_ERR_NOT_FOUND, @@ -345,8 +349,7 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, goto cont; } - int ret = asprintf(&poolid, "DiskPool/%s", pool_name); - + ret = asprintf(&poolid, "DiskPool/%s", pool_name); if (ret == -1) { CU_DEBUG("Failed to get disk poolid"); goto cont; diff --git a/src/Virt_VSMigrationService.c b/src/Virt_VSMigrationService.c index 4f48a68..d393787 100644 --- a/src/Virt_VSMigrationService.c +++ b/src/Virt_VSMigrationService.c @@ -1182,7 +1182,6 @@ static CMPIStatus ensure_dom_offline(virDomainPtr dom) static void clear_infstore_migration_flag(virDomainPtr dom) { struct infostore_ctx *infp; - bool ret = false; infp = infostore_open(dom); if (infp == NULL) { @@ -1191,7 +1190,7 @@ static void clear_infstore_migration_flag(virDomainPtr dom) return; } - ret = infostore_set_bool(infp, "migrating", false); + infostore_set_bool(infp, "migrating", false); CU_DEBUG("Clearing infostore migrating flag"); infostore_close(infp); @@ -1475,7 +1474,6 @@ static CMPIStatus migrate_do(const CMPIObjectPath *ref, CMPIStatus s; CMPIObjectPath *job_op; struct migration_job *job; - CMPI_THREAD_TYPE thread; uint32_t retcode = 1; CMPIInstance *ind = NULL; CMPIInstance *inst = NULL; @@ -1517,7 +1515,7 @@ static CMPIStatus migrate_do(const CMPIObjectPath *ref, if (!rc) CU_DEBUG("Failed to raise indication"); - thread = _BROKER->xft->newThread((void*)migration_thread, job, 0); + _BROKER->xft->newThread((void*)migration_thread, job, 0); retcode = CIM_SVPC_RETURN_JOB_STARTED; diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c index 5229f56..f8c5f24 100644 --- a/src/Virt_VirtualSystemManagementService.c +++ b/src/Virt_VirtualSystemManagementService.c @@ -1381,10 +1381,9 @@ static const char *input_rasd_to_vdev(CMPIInstance *inst, struct virt_device *dev) { const char *val; - const char *msg; if (cu_get_str_prop(inst, "ResourceSubType", &val) != CMPI_RC_OK) { - msg = "InputRASD ResourceSubType field not valid"; + CU_DEBUG("InputRASD ResourceSubType field not valid"); goto out; } dev->dev.input.type = strdup(val); @@ -1395,7 +1394,7 @@ static const char *input_rasd_to_vdev(CMPIInstance *inst, else if (STREQC(dev->dev.input.type, "tablet")) dev->dev.input.bus = strdup("usb"); else { - msg = "Invalid value for ResourceSubType in InputRASD"; + CU_DEBUG("Invalid value for ResourceSubType in InputRASD"); goto out; } } else -- 1.7.7.5 From veillard at redhat.com Thu Jan 12 05:56:31 2012 From: veillard at redhat.com (Daniel Veillard) Date: Thu, 12 Jan 2012 13:56:31 +0800 Subject: [Libvirt-cim] [PATCHv2] Remove compilation warnings In-Reply-To: <1326217662-8281-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326217662-8281-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <20120112055631.GN31327@redhat.com> On Tue, Jan 10, 2012 at 03:47:42PM -0200, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > I am building libvirt-cim with gcc 4.6.3 in fedora 16 and got a bunch of new > warnings. Most of them are about variables that are set but not used anywhere, > but there is one possible access to unitialized variables in Virt_RASD.c which > might result in unexpected behavior. > > xmlgen.c: In function 'system_xml': > xmlgen.c:633:28: error: variable 'bl' set but not used [-Werror=unused-but-set-variable] > xmlgen.c:642:28: error: variable 'bl_args' set but not used [-Werror=unused-but-set-variable] > xmlgen.c: In function 'disk_pool_xml': > xmlgen.c:1244:20: error: variable 'path' set but not used [-Werror=unused-but-set-variable] > xmlgen.c: In function 'filter_to_xml': > xmlgen.c:1474:15: error: variable 'msg' set but not used [-Werror=unused-but-set-variable] > > Virt_FilterEntry.c: In function 'enum_filter_rules': > Virt_FilterEntry.c:576:30: error: variable 'class_type' set but not used [-Werror=unused-but-set-variable] > > Virt_RASD.c: In function 'rasd_from_vdev': > Virt_RASD.c:406:27: error: 'pool' may be used uninitialized in this function [-Werror=uninitialized] > Virt_RASD.c:330:27: note: 'pool' was declared here > Virt_RASD.c:407:26: error: 'vol' may be used uninitialized in this function [-Werror=uninitialized] > Virt_RASD.c:320:26: note: 'vol' was declared here > > Virt_VSMigrationService.c: In function 'clear_infstore_migration_flag': > Virt_VSMigrationService.c:1185:15: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] > Virt_VSMigrationService.c: In function 'migrate_do': > Virt_VSMigrationService.c:1478:15: error: variable 'thread' set but not used [-Werror=unused-but-set-variable] > > Virt_Device.c: In function 'device_instances': > Virt_Device.c:431:15: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] > Virt_Device.c: In function 'proc_dev_list': > Virt_Device.c:657:13: error: variable 'rc' set but not used [-Werror=unused-but-set-variable] > Virt_Device.c: In function 'get_device_by_name': > Virt_Device.c:769:21: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] > Virt_Device.c:729:15: error: variable 'rc' set but not used [-Werror=unused-but-set-variable] > > Virt_VirtualSystemManagementService.c: In function 'input_rasd_to_vdev': > Virt_VirtualSystemManagementService.c:1384:21: error: variable 'msg' set but not used [-Werror=unused-but-set-variable] > > Changes since v1: > - xmlgen.c: Keep 'path' variable and fix value check. I'm seeing those too, so it would be nice to fix :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel at veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/ From veillard at redhat.com Thu Jan 12 06:26:10 2012 From: veillard at redhat.com (Daniel Veillard) Date: Thu, 12 Jan 2012 14:26:10 +0800 Subject: [Libvirt-cim] [PATCH] Fix a problem with multi-arch Message-ID: <20120112062610.GB3609@redhat.com> [ We carry the following patch in RHEL builds, I think it's best applied upstream :-) ] The /etc/ld.so.conf.d/libvirt-cim.conf file generated conflicted between 23 bits and 64 bits arches leading to a multi-arch conflict. Simply use a filename based on the expected architecture. Signed-off-by: Daniel Veillard diff --git a/libvirt-cim.spec.in b/libvirt-cim.spec.in index f3289db..d78eee7 100644 --- a/libvirt-cim.spec.in +++ b/libvirt-cim.spec.in @@ -54,7 +54,7 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/cmpi/*.la rm -f $RPM_BUILD_ROOT%{_libdir}/cmpi/*.a rm -f $RPM_BUILD_ROOT%{_libdir}/libxkutil.so mkdir -p $RPM_BUILD_ROOT/etc/ld.so.conf.d -echo %{_libdir}/cmpi > $RPM_BUILD_ROOT/etc/ld.so.conf.d/libvirt-cim.conf +echo %{_libdir}/cmpi > $RPM_BUILD_ROOT/etc/ld.so.conf.d/libvirt-cim.%{_arch}.conf mkdir -p $RPM_BUILD_ROOT at INFO_STORE@ %clean @@ -135,7 +135,7 @@ rm -fr $RPM_BUILD_ROOT %{_datadir}/libvirt-cim/cimv*-cimv2_mof %{_datadir}/libvirt-cim/*.registration %{_datadir}/libvirt-cim/cim_schema_*-MOFs.zip -%{_sysconfdir}/ld.so.conf.d/libvirt-cim.conf +%{_sysconfdir}/ld.so.conf.d/libvirt-cim.%{_arch}.conf %config(noreplace) %{_sysconfdir}/libvirt-cim.conf %changelog -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel at veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/ From xiawenc at linux.vnet.ibm.com Thu Jan 12 09:46:49 2012 From: xiawenc at linux.vnet.ibm.com (Wayne Xia) Date: Thu, 12 Jan 2012 17:46:49 +0800 Subject: [Libvirt-cim] [V3 PATCH 05/10] add a CIM model helper in libxkutil In-Reply-To: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1326361614-18674-6-git-send-email-xiawenc@linux.vnet.ibm.com> Added a CIM model helper file which contains all string genereation for network model. It also make libxkutil depends on libnetwork for that it used some function in libnetwork. Signed-off-by: Wayne Xia --- libxkutil/Makefile.am | 12 +- libxkutil/network_model_helper.c | 466 ++++++++++++++++++++++++++++++++++++++ libxkutil/network_model_helper.h | 105 +++++++++ 3 files changed, 580 insertions(+), 3 deletions(-) create mode 100644 libxkutil/network_model_helper.c create mode 100644 libxkutil/network_model_helper.h diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am index f6abce5..fb14f28 100644 --- a/libxkutil/Makefile.am +++ b/libxkutil/Makefile.am @@ -1,19 +1,25 @@ # Copyright IBM Corp. 2007 +# Modified by: +# Wenchao Xia, +# Now libxutil would include libnetwork. + SUBDIRS = tests AM_CFLAGS = $(CFLAGS_STRICT) \ -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ - pool_parsing.h acl_parsing.h + pool_parsing.h acl_parsing.h network_model_helper.h lib_LTLIBRARIES = libxkutil.la libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ - xmlgen.c infostore.c pool_parsing.c acl_parsing.c + xmlgen.c infostore.c pool_parsing.c acl_parsing.c \ + network_model_helper.c libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ - @LIBUUID_LIBS@ + @LIBUUID_LIBS@ \ + ${top_builddir}/libnetwork/libnetwork.la noinst_PROGRAMS = xml_parse_test diff --git a/libxkutil/network_model_helper.c b/libxkutil/network_model_helper.c new file mode 100644 index 0000000..7249b1b --- /dev/null +++ b/libxkutil/network_model_helper.c @@ -0,0 +1,466 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "network_model_helper.h" +#include "device_parsing.h" + +#include "cmpidt.h" +#include "cmpift.h" +#include "cmpimacs.h" + +/* this function would return a new allocated string or NULL */ +char *compare_and_switch_prefix(const char *orig_str, + const char *orig_prefix, + const char *dest_prefix) +{ + int orig_prefix_len, dest_prefix_len, asret; + char *retstr = NULL; + const char *suffix; + if (orig_str == NULL) { + goto out; + } + orig_prefix_len = strlen(orig_prefix); + dest_prefix_len = strlen(dest_prefix); + if (0 != strncmp(orig_str, orig_prefix, orig_prefix_len)) { + goto out; + } + suffix = orig_str + orig_prefix_len; + asret = asprintf(&retstr, "%s%s", dest_prefix, suffix); + if (asret == -1) { + free(retstr); + retstr = NULL; + } + out: + return retstr; +} + +char *switch_device_id_prefix(const char *whole_id, + const char *orig_prefix, + const char *dest_prefix) +{ + char *system = NULL; + char *device = NULL; + char *new_id = NULL; + char *retstr = NULL; + int asret; + + + if (0 == parse_fq_devid(whole_id, &system, &device)) { + goto out; + } + + new_id = compare_and_switch_prefix(device, + orig_prefix, dest_prefix); + + if (new_id == NULL) { + goto out; + } + asret = asprintf(&retstr, "%s/%s", system, new_id); + if (asret == -1) { + free(retstr); + retstr = NULL; + } + + out: + free(system); + free(device); + free(new_id); + return retstr; +} + +char *ep_id_to_easdea_id(const char *epid) +{ + return switch_device_id_prefix(epid, + ETHPORT_PREFIX, ETHPORT_ALLOCATION_SD_PREFIX); +} + +char *easdea_id_to_ep_id(const char *epid) +{ + return switch_device_id_prefix(epid, + ETHPORT_ALLOCATION_SD_PREFIX, ETHPORT_PREFIX); +} + +char *ep_id_to_easdec_id(const char *epid) +{ + return switch_device_id_prefix(epid, + ETHPORT_PREFIX, ETHPORT_CONNECTION_SD_PREFIX); +} + +char *easdec_id_to_ep_id(const char *epid) +{ + return switch_device_id_prefix(epid, + ETHPORT_CONNECTION_SD_PREFIX, ETHPORT_PREFIX); +} + +char *vlanid_to_connection_name(const int id) +{ + int asret; + char *str = NULL; + char *prefix = CONNECTION_VLAN_PREFIX; + asret = asprintf(&str, "%s%d", prefix, id); + if (asret == -1) { + return NULL; + } + return str; +} + +int vlanid_from_connection_name(const char *name) +{ + int id = -1; + int temp = -1; + char *prefix = CONNECTION_VLAN_PREFIX; + char *dig_start, *dig_end; + if (name == NULL) { + goto out; + } + dig_start = strstr(name, prefix); + if (dig_start == NULL) { + goto out; + } + dig_start += strlen(prefix); + temp = strtol(dig_start, &dig_end, 10); + if ((dig_start == dig_end) || (temp < 0) || (temp > 4095)) { + goto out; + } + id = temp; + out: + return id; +} + +int eth_iface_filter_cim_ethport(const EthIface *piface, + void *nouse) +{ + if ((piface->eth_type & ETH_TYPE_ETHER_ANY) && + (!(piface->eth_type & ETH_TYPE_ETHER_SUB_BRIDGE))) { + return 1; + } + return 0; +} + +int eth_iface_filter_cim_ethport_for_name(const EthIface *piface, + void *name) +{ + int cim_ethport_flag; + cim_ethport_flag = eth_iface_filter_cim_ethport(piface, NULL); + if (cim_ethport_flag == 1) { + if (0 == strcmp(piface->name, name)) { + return 1; + } + } + return 0; +} + +/* returned value need to be freed */ +char *get_ethportsd_name_from_iface(const char *iface_name, const int type) +{ + char *prefix; + char *name; + int size; + + if (iface_name == NULL) { + return NULL; + } + + if (type == EASD_TYPE_EA) { + prefix = ETHPORT_ALLOCATION_SD_PREFIX; + } else { + prefix = ETHPORT_CONNECTION_SD_PREFIX; + } + + size = strlen(iface_name)+strlen(prefix)+1; + SAFE_MALLOC(name, size); + snprintf(name, size, "%s%s", prefix, iface_name); + return name; +} + +/* returned value need to be freed */ +char *get_iface_name_from_ethportsd(const char *ethport_name, int *ptype) +{ + char *prefix; + char *name = NULL; + int size; + int prefix_len; + int t = -1; + + if (ethport_name == NULL) { + goto out; + } + + prefix = ETHPORT_ALLOCATION_SD_PREFIX; + prefix_len = strlen(prefix); + if (0 != strncmp(ethport_name, prefix, prefix_len)) { + prefix = ETHPORT_CONNECTION_SD_PREFIX; + prefix_len = strlen(prefix); + if (0 != strncmp(ethport_name, prefix, prefix_len)) { + goto out; + } else { + t = EASD_TYPE_EC; + } + } else { + t = EASD_TYPE_EA; + } + size = strlen(ethport_name)-strlen(prefix)+1; + SAFE_MALLOC(name, size); + snprintf(name, size, "%s", ethport_name+prefix_len); + + out: + if (ptype != NULL) { + *ptype = t; + } + return name; +} + +int eth_iface_filter_cim_switch(const EthIface *piface, + void *nouse) +{ + if ((piface->eth_type & ETH_TYPE_ETHER_ANY) && + (piface->eth_type & ETH_TYPE_ETHER_SUB_BRIDGE)) { + return 1; + } + return eth_iface_filter_peths(piface, nouse); +} + +int eth_iface_filter_cim_switch_for_name(const EthIface *piface, + void *name) +{ + int cim_switch_flag; + cim_switch_flag = eth_iface_filter_cim_switch(piface, NULL); + if (cim_switch_flag == 1) { + if (0 == strcmp(piface->name, name)) { + return 1; + } + } + return 0; +} + +/* returned value need to be freed */ +char *get_switch_name_from_iface(const char *iface_name) +{ + char *prefix = SWITCH_PREFIX; + char *name; + int size; + + size = strlen(iface_name)+strlen(prefix)+1; + SAFE_MALLOC(name, size); + snprintf(name, size, "%s%s", prefix, iface_name); + return name; +} + +/* returned value need to be freed */ +char *get_iface_name_from_switch(const char *switch_name) +{ + char *prefix = SWITCH_PREFIX; + char *name; + int size; + int prefix_len; + + prefix_len = strlen(prefix); + if (0 != strncmp(switch_name, prefix, prefix_len)) { + return NULL; + } + size = strlen(switch_name)-strlen(prefix)+1; + SAFE_MALLOC(name, size); + snprintf(name, size, "%s", switch_name+prefix_len); + return name; +} + +/* returned value need to be freed */ +char *get_ethport_name_from_iface(const char *iface_name) +{ + char *prefix; + char *name; + int size; + + if (iface_name == NULL) { + return NULL; + } + + prefix = ETHPORT_PREFIX; + size = strlen(iface_name)+strlen(prefix)+1; + SAFE_MALLOC(name, size); + snprintf(name, size, "%s%s", prefix, iface_name); + return name; +} + +/* returned value need to be freed */ +char *get_iface_name_from_ethport(const char *ethport_name) +{ + char *prefix = ETHPORT_PREFIX; + char *name = NULL; + int size; + int prefix_len; + + if (ethport_name == NULL) { + goto out; + } + + prefix = ETHPORT_PREFIX; + prefix_len = strlen(prefix); + if (0 != strncmp(ethport_name, prefix, prefix_len)) { + goto out; + } + size = strlen(ethport_name)-prefix_len+1; + SAFE_MALLOC(name, size); + snprintf(name, size, "%s", ethport_name+prefix_len); + + out: + return name; +} + +int get_possible_bridge_name_for_cim_model(EthIface *piface, + char **pbr1name, char **pbr2name) +{ + char *br1_name; + char *br2_name; + if (piface->attach_bridge != NULL) { + br1_name = get_switch_name_from_iface(piface->attach_bridge); + } else if (piface->dep_ifname != NULL) { + br1_name = get_switch_name_from_iface(piface->dep_ifname); + } else if ((piface->eth_type & ETH_TYPE_ETHER_ANY) && + (piface->eth_type & ETH_TYPE_ETHER_SUB_PHYSICAL)) { + br1_name = get_switch_name_from_iface(piface->name); + } else { + br1_name = NULL; + } + + if ((piface->attach_bridge != NULL) && (piface->dep_ifname != NULL)) { + br2_name = get_switch_name_from_iface(piface->dep_ifname); + } else { + br2_name = NULL; + } + + *pbr1name = br1_name; + *pbr2name = br2_name; + return 1; +} + +CMPIStatus get_array_uint16_from_instance(const CMPIBroker *broker, + CMPIInstance *inst, + char *array_name, + int *ret_result, + int *ret_size, + int max_size) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIArray *array; + CMPICount array_size; + CMPIData elem; + int i, ret, count = 0; + + ret = cu_get_array_prop(inst, array_name, &array); + if (ret != CMPI_RC_OK) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "array property not found."); + CU_DEBUG("Failed to get array property %s.", array_name); + goto out; + } + array_size = CMGetArrayCount(array, &s); + if ((s.rc != CMPI_RC_OK) || (array_size > max_size) || + (array_size <= 0)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to get size of array property," + " or its size is 0 or too big."); + CU_DEBUG("failed in getting size of %s property.", array_name); + goto out; + } + for (i = 0; i < array_size; i++) { + elem = CMGetArrayElementAt(array, i, NULL); + if (CMIsNullValue(elem)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "NULL content of array property."); + CU_DEBUG("NULL content of %s property.", array_name); + goto out; + } + if (!(elem.type & CMPI_INTEGER)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "wrong type of array property."); + CU_DEBUG("wrong type of %s property.", array_name); + goto out; + } + ret_result[count] = elem.value.uint16; + count++; + } + out: + *ret_size = count; + return s; +} + +CMPIStatus get_array_string_from_instance(const CMPIBroker *broker, + CMPIInstance *inst, + char *array_name, + char **ret_result, + int *ret_size, + int max_size) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIArray *array; + CMPICount array_size; + CMPIData elem; + const char *str; + int i, ret, count = 0; + + ret = cu_get_array_prop(inst, array_name, &array); + if (ret != CMPI_RC_OK) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "array property not found."); + CU_DEBUG("Failed to get array property %s.", array_name); + goto out; + } + array_size = CMGetArrayCount(array, &s); + if ((s.rc != CMPI_RC_OK) || (array_size > max_size) || + (array_size <= 0)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to get size of array property," + " or its size is 0 or too big."); + CU_DEBUG("failed in getting size of %s property.", array_name); + goto out; + } + for (i = 0; i < array_size; i++) { + elem = CMGetArrayElementAt(array, i, NULL); + if (CMIsNullValue(elem)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "NULL content of array property."); + CU_DEBUG("NULL content of %s property.", array_name); + goto out; + } + str = NULL; + str = CMGetCharPtr(elem.value.string); + if (str == NULL) { + CU_DEBUG("Could not extract char pointer from " + "CMPIArray %s.", array_name); + goto out; + } + ret_result[count] = SAFE_STRDUP(str); + count++; + } + out: + *ret_size = count; + return s; +} diff --git a/libxkutil/network_model_helper.h b/libxkutil/network_model_helper.h new file mode 100644 index 0000000..6f501c3 --- /dev/null +++ b/libxkutil/network_model_helper.h @@ -0,0 +1,105 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NETWORK_MODEL_HELPER_H +#define NETWORK_MODEL_HELPER_H + +#include "libnetwork/host_network_API.h" + +#define EASD_TYPE_EA 1 +#define EASD_TYPE_EC 2 + +#define NETWORK_CLASS_PREFIX "Net" + +#define SWITCH_PREFIX "VS_" +#define VESSD_SYSTEM_PREFIX "Virt" +#define ETHPORT_PREFIX "EP_" +#define ETHPORT_ALLOCATION_SD_PREFIX "EA_" +#define ETHPORT_CONNECTION_SD_PREFIX "EC_" + +#define CONNECTION_VLAN_PREFIX "VLAN" + +#define CIM_NUM_NET_ETHERNET 2 +#define CIM_NUM_SWITCH_DEDICATED 38 +#define CIM_NUM_SWITCHPORT 30 +#define CIM_NUM_VLAN_MODE_TRUNK 5 +#define CIM_NUM_CONSUMERVISIBILITY_PASSEDTHROUGH 2 +#define CIM_NUM_CONSUMERVISIBILITY_VIRTUALIZED 3 + +char *get_switch_name_from_iface(const char *iface_name); +char *get_iface_name_from_switch(const char *switch_name); + +char *get_ethport_name_from_iface(const char *iface_name); +char *get_iface_name_from_ethport(const char *ethport_name); + +char *get_ethportsd_name_from_iface(const char *iface_name, const int type); +char *get_iface_name_from_ethportsd(const char *ethport_name, int *ptype); + +char *ep_id_to_easdea_id(const char *epid); +char *easdea_id_to_ep_id(const char *epid); +char *ep_id_to_easdec_id(const char *epid); +char *easdec_id_to_ep_id(const char *epid); + +char *vlanid_to_connection_name(const int id); +int vlanid_from_connection_name(const char *name); + + + + + +int eth_iface_filter_cim_switch(const EthIface *piface, + void *nouse); +int eth_iface_filter_cim_switch_for_name(const EthIface *piface, + void *name); +int eth_iface_filter_cim_ethport(const EthIface *piface, + void *nouse); +int eth_iface_filter_cim_ethport_for_name(const EthIface *piface, + void *name); + +int get_possible_bridge_name_for_cim_model(EthIface *piface, + char **pbr1name, char **pbr2name); + + +char *compare_and_switch_prefix(const char *orig_str, + const char *orig_prefix, + const char *dest_prefix); + +char *switch_device_id_prefix(const char *whole_id, + const char *orig_prefix, + const char *dest_prefix); + +/* other help function related to CIM */ +CMPIStatus get_array_uint16_from_instance(const CMPIBroker *broker, + CMPIInstance *inst, + char *array_name, + int *ret_result, + int *ret_size, + int max_size); + +CMPIStatus get_array_string_from_instance(const CMPIBroker *broker, + CMPIInstance *inst, + char *array_name, + char **ret_result, + int *ret_size, + int max_size); + + +#endif -- 1.7.6 From xiawenc at linux.vnet.ibm.com Thu Jan 12 09:46:48 2012 From: xiawenc at linux.vnet.ibm.com (Wayne Xia) Date: Thu, 12 Jan 2012 17:46:48 +0800 Subject: [Libvirt-cim] [V3 PATCH 04/10] libnetwork source code with a test program In-Reply-To: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1326361614-18674-5-git-send-email-xiawenc@linux.vnet.ibm.com> source code of libnetwor and test program. Calling stack is: main->host_network_API->host_network_implement_OSAPI->(libnl3 libbridge). dll_magic.h is the file used to distinguish whether the symbol is exported or imported. Signed-off-by: Wayne Xia --- libnetwork/dll_magic.h | 13 + libnetwork/host_network_API.c | 30 ++ libnetwork/host_network_API.h | 25 ++ libnetwork/host_network_basic.c | 657 ++++++++++++++++++++++++++++ libnetwork/host_network_basic.h | 170 ++++++++ libnetwork/host_network_error.h | 31 ++ libnetwork/host_network_helper.c | 659 +++++++++++++++++++++++++++++ libnetwork/host_network_helper.h | 202 +++++++++ libnetwork/host_network_implement_OSAPI.c | 453 ++++++++++++++++++++ libnetwork/host_network_implement_OSAPI.h | 21 + libnetwork/libnetwork_test.c | 82 ++++ 11 files changed, 2343 insertions(+), 0 deletions(-) create mode 100644 libnetwork/dll_magic.h create mode 100644 libnetwork/host_network_API.c create mode 100644 libnetwork/host_network_API.h create mode 100644 libnetwork/host_network_basic.c create mode 100644 libnetwork/host_network_basic.h create mode 100644 libnetwork/host_network_error.h create mode 100644 libnetwork/host_network_helper.c create mode 100644 libnetwork/host_network_helper.h create mode 100644 libnetwork/host_network_implement_OSAPI.c create mode 100644 libnetwork/host_network_implement_OSAPI.h create mode 100644 libnetwork/libnetwork_test.c diff --git a/libnetwork/dll_magic.h b/libnetwork/dll_magic.h new file mode 100644 index 0000000..36bca83 --- /dev/null +++ b/libnetwork/dll_magic.h @@ -0,0 +1,13 @@ +#ifndef DLL_MAGIC_H +#define DLL_MAGIC_H + + +#if __GNUC__ >= 4 + #ifdef DLL_BUILD + #define DLL_PUBLIC __attribute__ ((visibility ("default"))) + #else + #define DLL_PUBLIC + #endif +#endif + +#endif diff --git a/libnetwork/host_network_API.c b/libnetwork/host_network_API.c new file mode 100644 index 0000000..d2838ad --- /dev/null +++ b/libnetwork/host_network_API.c @@ -0,0 +1,30 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + + +#include "host_network_API.h" +#include "host_network_implement_OSAPI.h" +#include "host_network_error.h" + +/* this layer is added to devide the abstraction and implemention, so that + different implemention could be used and switched */ + +int get_host_ifaces(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque) +{ + return get_host_eth_ifaces_osapi(plist, filter_func, filter_opaque); +} + +char *get_host_iface_error_reason(int errno) +{ + return translate_error_no(errno); +} diff --git a/libnetwork/host_network_API.h b/libnetwork/host_network_API.h new file mode 100644 index 0000000..452aa29 --- /dev/null +++ b/libnetwork/host_network_API.h @@ -0,0 +1,25 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#ifndef HOST_NETWORK_API +#define HOST_NETWORK_API + +#include "dll_magic.h" +#include "host_network_basic.h" +#include "host_network_helper.h" + +DLL_PUBLIC int get_host_ifaces(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque); + +DLL_PUBLIC char *get_host_iface_error_reason(int errno); + +#endif diff --git a/libnetwork/host_network_basic.c b/libnetwork/host_network_basic.c new file mode 100644 index 0000000..e227091 --- /dev/null +++ b/libnetwork/host_network_basic.c @@ -0,0 +1,657 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include "host_network_basic.h" +#include "host_network_helper.h" + +#include +#include +#include + +static void vlan_prop_print(VLAN_Prop *pvlan_prop) +{ + VLAN_Prop_8021q *p_8021q; + char *ingress = NULL, *egress = NULL; + CMD_DEBUG(1, "--VLAN props: type %d.\n", + pvlan_prop->vlan_type); + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + vlan_8021q_qos_num_to_str(&ingress, &(p_8021q->ingress)); + vlan_8021q_qos_num_to_str(&egress, &(p_8021q->egress)); + CMD_DEBUG(1, "----IEEE802.1.Q: id %d, reorder %d, priority %d, " + "ingress %s, egress %s, parent %s.\n", + p_8021q->vlan_id, p_8021q->reorder_hdr, p_8021q->priv_flag, + ingress, egress, p_8021q->parent); + } + SAFE_FREE(ingress); + SAFE_FREE(egress); +} + +static void br_prop_print(BR_Prop *pbr_prop) +{ + int i = 0; + CMD_DEBUG(1, "--Bridge props: id %s, stp %d, " + "bridge type %d, port_num %d.\n", + pbr_prop->bridge_id, pbr_prop->STP, + pbr_prop->type, pbr_prop->port_num); + if (pbr_prop->port_names != NULL) { + CMD_DEBUG(1, "----Ports attached: "); + while (i < pbr_prop->port_num) { + CMD_DEBUG(1, " %s,", *(pbr_prop->port_names+i)); + i++; + } + CMD_DEBUG(1, "\n"); + } +} + +void eth_iface_print(EthIface *piface) +{ + CMD_DEBUG(1, "Iface device: name %s.\n" + "--Main Props: parent %s, attach to %s, mac %s, ip %s, ip_mask %s," + " RX %lld, TX %lld, state %d, iface type 0x%x.\n", + piface->name, piface->dep_ifname, piface->attach_bridge, + piface->mac, piface->ipv4_prop.ip, piface->ipv4_prop.ip_mask, + piface->run_prop.rx_bytes, piface->run_prop.tx_bytes, + piface->run_prop.state, piface->eth_type); + if (piface->pbr_prop != NULL) { + br_prop_print(piface->pbr_prop); + } + if (piface->pvlan_prop != NULL) { + vlan_prop_print(piface->pvlan_prop); + } + return; +} + +void eth_ifaceslist_print(EthIfacesList *plist) +{ + int i = 0; + CMD_DEBUG(1, "Have %d ifaces in the list:\n", plist->count); + while (i < plist->count) { + CMD_DEBUG(1, "%04d ", i); + eth_iface_print(plist->pifaces[i]); + i++; + } +} + +void vlan_prop_init(VLAN_Prop *pvlan_prop, int vlan_type) +{ + VLAN_Prop_8021q *p_8021q; + memset(pvlan_prop, 0, sizeof(VLAN_Prop)); + pvlan_prop->vlan_type = vlan_type; + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + p_8021q->ingress.count = NUM_NOT_GOT; + p_8021q->egress.count = NUM_NOT_GOT; + p_8021q->vlan_id = NUM_NOT_GOT; + p_8021q->reorder_hdr = NUM_NOT_GOT; + p_8021q->priv_flag = NUM_NOT_GOT; + } +} + +void br_prop_init(BR_Prop *pbr_prop) +{ + memset(pbr_prop, 0, sizeof(BR_Prop)); + pbr_prop->STP = NUM_NOT_GOT; + pbr_prop->type = BR_TYPE_NOT_GOT; + pbr_prop->port_num = NUM_NOT_GOT; +} + +void eth_iface_init(EthIface *piface) +{ + memset(piface, 0, sizeof(EthIface)); + piface->eth_type = ETH_TYPE_NOT_GOT; + piface->run_prop.rx_bytes = NUM_NOT_GOT; + piface->run_prop.tx_bytes = NUM_NOT_GOT; + piface->run_prop.state = ETH_STATE_NOT_GOT; + return; +} + +void eth_iface_add_br_prop(EthIface *piface) +{ + SAFE_MALLOC(piface->pbr_prop, sizeof(BR_Prop)); + br_prop_init(piface->pbr_prop); +} + +void eth_iface_add_vlan_prop(EthIface *piface, int vlan_type) +{ + SAFE_MALLOC(piface->pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(piface->pvlan_prop, vlan_type); +} + +void vlan_prop_uninit(VLAN_Prop *pvlan_prop) +{ + VLAN_Prop_8021q *p_8021q; + if (pvlan_prop == NULL) { + return; + } + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + SAFE_FREE(p_8021q->parent); + } +} + +void br_prop_uninit(BR_Prop *pbr_prop) +{ + int i; + if (pbr_prop == NULL) { + return; + } + SAFE_FREE(pbr_prop->bridge_id); + i = 0; + if (pbr_prop->port_names != NULL) { + while (i < pbr_prop->port_num) { + SAFE_FREE(pbr_prop->port_names[i]); + i++; + } + SAFE_FREE(pbr_prop->port_names); + } +} + +void eth_iface_uninit(EthIface *piface) +{ + if (piface == NULL) { + return; + } + SAFE_FREE(piface->name); + SAFE_FREE(piface->dep_ifname); + SAFE_FREE(piface->attach_bridge); + SAFE_FREE(piface->mac); + SAFE_FREE(piface->ipv4_prop.ip); + SAFE_FREE(piface->ipv4_prop.ip_mask); + br_prop_uninit(piface->pbr_prop); + SAFE_FREE(piface->pbr_prop); + vlan_prop_uninit(piface->pvlan_prop); + SAFE_FREE(piface->pvlan_prop); + return; +} + +void eth_ifaces_clear(EthIface **ppifaces, int num) +{ + EthIface **t; + int i; + if (num <= 0) { + return; + } + t = ppifaces; + i = 0; + while (i < num) { + if (*t != NULL) { + eth_iface_uninit(*t); + SAFE_FREE(*t); + } + t++; + i++; + } + return; +} + +void eth_ifaceslist_init(EthIfacesList *plist) +{ + plist->count = 0; +} + +void eth_ifaceslist_uninit(EthIfacesList *plist) +{ + eth_ifaces_clear(plist->pifaces, plist->count); +} + +static void vlan_prop_dup(VLAN_Prop *dest, const VLAN_Prop *src) +{ + VLAN_Prop_8021q *pd_8021q; + const VLAN_Prop_8021q *ps_8021q; + dest->vlan_type = src->vlan_type; + if (dest->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q = &(dest->props.prop_8021q); + ps_8021q = &(src->props.prop_8021q); + pd_8021q->vlan_id = ps_8021q->vlan_id; + pd_8021q->reorder_hdr = ps_8021q->reorder_hdr; + pd_8021q->priv_flag = ps_8021q->priv_flag; + pd_8021q->ingress = ps_8021q->ingress; + pd_8021q->egress = ps_8021q->egress; + pd_8021q->parent = SAFE_STRDUP(ps_8021q->parent); + } +} + +static void br_prop_dup(BR_Prop *dest, const BR_Prop *src) +{ + int i; + dest->bridge_id = SAFE_STRDUP(src->bridge_id); + dest->STP = src->STP; + dest->type = src->type; + SAFE_PSTR_ARRAY_DUP(dest->port_names, dest->port_num, + src->port_names, src->port_num, i); +} + +void eth_iface_dup(EthIface *dest, const EthIface *src) +{ + dest->name = SAFE_STRDUP(src->name); + dest->dep_ifname = SAFE_STRDUP(src->dep_ifname); + dest->attach_bridge = SAFE_STRDUP(src->attach_bridge); + dest->mac = SAFE_STRDUP(src->mac); + dest->eth_type = src->eth_type; + dest->ipv4_prop.ip = SAFE_STRDUP(src->ipv4_prop.ip); + dest->ipv4_prop.ip_mask = SAFE_STRDUP(src->ipv4_prop.ip_mask); + dest->run_prop.rx_bytes = src->run_prop.rx_bytes; + dest->run_prop.tx_bytes = src->run_prop.tx_bytes; + dest->run_prop.state = src->run_prop.state; + + if (src->pbr_prop != NULL) { + SAFE_MALLOC(dest->pbr_prop, sizeof(BR_Prop)); + /* doesn't need init it for that it would be copied at once */ + br_prop_dup(dest->pbr_prop, src->pbr_prop); + } else { + dest->pbr_prop = NULL; + } + + if (src->pvlan_prop != NULL) { + SAFE_MALLOC(dest->pvlan_prop, sizeof(VLAN_Prop)); + /* doesn't need init it for that it would be copied at once */ + vlan_prop_dup(dest->pvlan_prop, src->pvlan_prop); + } else { + dest->pvlan_prop = NULL; + } + +} + +int eth_iface_compare(const EthIface *p1, const EthIface *p2) +{ + int ret = 0; + if ((p1->name != NULL) || (p2->name != NULL)) { + if (0 == strcmp(p1->name, p2->name)) { + ret = 1; + } + } + return ret; +} + +static void vlan_prop_merge(VLAN_Prop *pdest, VLAN_Prop *psrc, int style) +{ + VLAN_Prop_8021q *pd_8021q, *ps_8021q; + + NUM_MERGE(pdest->vlan_type, psrc->vlan_type, VLAN_TYPE_NOT_GOT); + + if (psrc->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q = &(pdest->props.prop_8021q); + ps_8021q = &(psrc->props.prop_8021q); + NUM_MERGE(pd_8021q->vlan_id, ps_8021q->vlan_id, NUM_NOT_GOT); + NUM_MERGE(pd_8021q->reorder_hdr, ps_8021q->reorder_hdr, NUM_NOT_GOT); + NUM_MERGE(pd_8021q->priv_flag, ps_8021q->priv_flag, NUM_NOT_GOT); + if (pd_8021q->ingress.count == NUM_NOT_GOT) { + pd_8021q->ingress = ps_8021q->ingress; + } + if (pd_8021q->egress.count == NUM_NOT_GOT) { + pd_8021q->egress = ps_8021q->egress; + } + if (style == 0) { + CHARS_MERGE_NORMAL(pd_8021q->parent, ps_8021q->parent); + } else { + CHARS_MERGE_MOVE(pd_8021q->parent, ps_8021q->parent); + } + } +} + +static void br_prop_merge(BR_Prop *pdest, BR_Prop *psrc, int style) +{ + int i; + + if (style == 0) { + CHARS_MERGE_NORMAL(pdest->bridge_id, psrc->bridge_id); + /*merge it when dest have not been set */ + if (pdest->port_names == NULL) { + SAFE_PSTR_ARRAY_DUP(pdest->port_names, pdest->port_num, + psrc->port_names, psrc->port_num, i); + } + } else { + CHARS_MERGE_MOVE(pdest->bridge_id, psrc->bridge_id); + /*merge it when dest have not been set */ + if (pdest->port_names == NULL) { + pdest->port_names = psrc->port_names; + pdest->port_num = psrc->port_num; + psrc->port_names = NULL; + psrc->port_num = NUM_NOT_GOT; + } + } + NUM_MERGE(pdest->STP, psrc->STP, NUM_NOT_GOT); + NUM_MERGE(pdest->type, psrc->type, BR_TYPE_NOT_GOT); +} + +void eth_iface_merge(EthIface *dest, EthIface *src, int style) +{ + if (style == 0) { + CHARS_MERGE_NORMAL(dest->name, src->name); + CHARS_MERGE_NORMAL(dest->dep_ifname, src->dep_ifname); + CHARS_MERGE_NORMAL(dest->attach_bridge, src->attach_bridge); + CHARS_MERGE_NORMAL(dest->mac, src->mac); + CHARS_MERGE_NORMAL(dest->ipv4_prop.ip, src->ipv4_prop.ip); + CHARS_MERGE_NORMAL(dest->ipv4_prop.ip_mask, src->ipv4_prop.ip_mask); + } else { + CHARS_MERGE_MOVE(dest->name, src->name); + CHARS_MERGE_MOVE(dest->dep_ifname, src->dep_ifname); + CHARS_MERGE_MOVE(dest->attach_bridge, src->attach_bridge); + CHARS_MERGE_MOVE(dest->mac, src->mac); + CHARS_MERGE_MOVE(dest->ipv4_prop.ip, src->ipv4_prop.ip); + CHARS_MERGE_MOVE(dest->ipv4_prop.ip_mask, src->ipv4_prop.ip_mask); + } + + /* special case for eth_type*/ + if (dest->eth_type == ETH_TYPE_NOT_GOT) { + dest->eth_type = src->eth_type; + } else { + if ((src->eth_type & ETH_TYPE_ETHER_ANY) && + (dest->eth_type & ETH_TYPE_ETHER_ANY)) { + dest->eth_type |= (src->eth_type & ETH_TYPE_SUB_MASK); + } + } + + NUM_MERGE(dest->run_prop.rx_bytes, src->run_prop.rx_bytes, + NUM_NOT_GOT); + NUM_MERGE(dest->run_prop.tx_bytes, src->run_prop.tx_bytes, + NUM_NOT_GOT); + NUM_MERGE(dest->run_prop.state, src->run_prop.state, ETH_STATE_NOT_GOT); + + if (src->pbr_prop != NULL) { + if (dest->pbr_prop == NULL) { + SAFE_MALLOC(dest->pbr_prop, sizeof(BR_Prop)); + br_prop_init(dest->pbr_prop); + } + br_prop_merge(dest->pbr_prop, src->pbr_prop, style); + } + + if (src->pvlan_prop != NULL) { + if (dest->pvlan_prop == NULL) { + SAFE_MALLOC(dest->pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(dest->pvlan_prop, src->pvlan_prop->vlan_type); + } + vlan_prop_merge(dest->pvlan_prop, src->pvlan_prop, style); + } + +} + +/* compare qos values */ +static int VLAN_Qos_8021q_compare_by_ref(const VLAN_Qos_8021q *pqos, + const VLAN_Qos_8021q *pref) +{ + int ret = 1; + int i, j; + if (pref->count == NUM_NOT_GOT) { + /* do not need to compare*/ + goto out; + } + if ((pref->count < 0) || (pref->count > 8)) { + ret = 0; + goto out; + } + if ((pqos->count < 0) || (pqos->count > 8)) { + ret = 0; + goto out; + } + + i = 0; + while (i < pref->count) { + j = 0; + while (j < pqos->count) { + if (pref->values[i].from == pqos->values[j].from) { + if (pref->values[i].to != pqos->values[j].to) { + ret = 0; + goto out; + } + break; + } + j++; + } + if (j == pqos->count) { + ret = 0; + goto out; + } + i++; + } + + out: + return ret; +} + +static int vlan_prop_filter_by_ref(const VLAN_Prop *pvlan_prop, void *pref) +{ + int compare_result = 1; + VLAN_Prop *ref = (VLAN_Prop *)pref; + char *p1, *p2; + const VLAN_Prop_8021q *pd_8021q; + VLAN_Prop_8021q *pref_8021q; + + NUM_COMPARE_BY_REF(pvlan_prop->vlan_type, ref->vlan_type, + compare_result, VLAN_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + if (ref->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q = &(pvlan_prop->props.prop_8021q); + pref_8021q = &(ref->props.prop_8021q); + + NUM_COMPARE_BY_REF(pd_8021q->vlan_id, pref_8021q->vlan_id, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pd_8021q->reorder_hdr, pref_8021q->reorder_hdr, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pd_8021q->priv_flag, pref_8021q->priv_flag, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + compare_result = VLAN_Qos_8021q_compare_by_ref(&(pd_8021q->ingress), + &(pref_8021q->ingress)); + if (compare_result == 0) { + goto out; + } + + compare_result = VLAN_Qos_8021q_compare_by_ref(&(pd_8021q->egress), + &(pref_8021q->egress)); + if (compare_result == 0) { + goto out; + } + + p1 = pd_8021q->parent; + p2 = pref_8021q->parent; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + } + + out: + return compare_result; + +} + +static int br_prop_filter_by_ref(const BR_Prop *pbr_prop, void *pref) +{ + int compare_result = 1; + BR_Prop *ref = (BR_Prop *)pref; + char *p1, *p2; + + p1 = pbr_prop->bridge_id; + p2 = ref->bridge_id; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->STP, ref->STP, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->type, ref->type, + compare_result, BR_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->port_num, ref->port_num, + compare_result, NUM_NOT_GOT); + /* skip the comparation of ports it attached, user can define + a special filter for that */ + out: + return compare_result; +} + +int eth_iface_filter_by_ref(const EthIface *piface, void *pref) +{ + int compare_result = 1; + EthIface *ref = (EthIface *)pref; + char *p1, *p2; + + p1 = piface->name; + p2 = ref->name; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->dep_ifname; + p2 = ref->dep_ifname; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->attach_bridge; + p2 = ref->attach_bridge; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->mac; + p2 = ref->mac; + CHARS_COMPARE_CASE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + /* special case for eth_type */ + NUM_COMPARE_BY_REF((piface->eth_type & ETH_TYPE_BASE_MASK), + (ref->eth_type & ETH_TYPE_BASE_MASK), + compare_result, ETH_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + NUM_COMPARE_BY_REF((piface->eth_type & ETH_TYPE_SUB_MASK), + (ref->eth_type & ETH_TYPE_SUB_MASK), + compare_result, ETH_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + p1 = piface->ipv4_prop.ip; + p2 = ref->ipv4_prop.ip; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->ipv4_prop.ip_mask; + p2 = ref->ipv4_prop.ip_mask; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(piface->run_prop.state, ref->run_prop.state, + compare_result, ETH_STATE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + if (ref->pbr_prop != NULL) { + if (piface->pbr_prop != NULL) { + compare_result = br_prop_filter_by_ref(piface->pbr_prop, + ref->pbr_prop); + } else { + compare_result = 0; + } + if (compare_result == 0) { + goto out; + } + } + + if (ref->pvlan_prop != NULL) { + if (piface->pvlan_prop != NULL) { + compare_result = vlan_prop_filter_by_ref(piface->pvlan_prop, + ref->pvlan_prop); + + } else { + compare_result = 0; + } + if (compare_result == 0) { + goto out; + } + } + + out: + return compare_result; +} + +int eth_iface_filter_by_refname(const EthIface *piface, void *pref) +{ + int compare_result = 1; + EthIface *ref = (EthIface *)pref; + char *p1, *p2; + + p1 = piface->name; + p2 = ref->name; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + out: + return compare_result; +} + +int eth_iface_filter_vlans(const EthIface *piface, void *nouse) +{ + if (piface->name == NULL) { + return 0; + } + if (NULL == strstr(piface->name, ".")) { + return 0; + } else { + return 1; + } +} + +/* the judgement condition is weak, but I can't find a better way */ +int eth_iface_filter_peths(const EthIface *piface, void *nouse) +{ + if (piface->name == NULL) { + return 0; + } + if (NULL == strstr(piface->name, ".")) { + if (0 == strncmp(piface->name, "eth", 3)) { + return 1; + } else { + return 0; + } + } else { + return 0; + } +} diff --git a/libnetwork/host_network_basic.h b/libnetwork/host_network_basic.h new file mode 100644 index 0000000..bb92453 --- /dev/null +++ b/libnetwork/host_network_basic.h @@ -0,0 +1,170 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#ifndef NETWORK_BASIC_HOST_H +#define NETWORK_BASIC_HOST_H + +#include "dll_magic.h" + +/* value defines */ +#define MAX_IFACE_NUM 4096 + +#define NUM_NOT_GOT -1 + +typedef enum { + ETH_STATE_NOT_GOT = NUM_NOT_GOT, + ETH_STATE_UNKNOWN = 0, + ETH_STATE_DOWN = 1, + ETH_STATE_UP = 2 +} EthState; + +#define ETH_TYPE_BASE_MASK 0xff00 +#define ETH_TYPE_SUB_MASK 0x00ff +typedef enum { + ETH_TYPE_NOT_GOT = 0x0000, + ETH_TYPE_UNKNOWN = 0x0100, + ETH_TYPE_OTHER = 0x0200, + ETH_TYPE_ETHER_ANY = 0x0400, + ETH_TYPE_ETHER_SUB_PHYSICAL = 0x0001, + ETH_TYPE_ETHER_SUB_BRIDGE = 0x0002, + ETH_TYPE_ETHER_SUB_VLAN = 0x0004 +} EthType; + +typedef enum { + BR_TYPE_NOT_GOT = NUM_NOT_GOT, + BR_TYPE_UNKNOWN = 0, + BR_TYPE_SWITCH = 1, + BR_TYPE_NAT = 2 +} BrType; + +typedef enum { + VLAN_TYPE_NOT_GOT = NUM_NOT_GOT, + VLAN_TYPE_802_1_Q = 1, + VLAN_TYPE_802_1_QBG = 2, + VLAN_TYPE_802_1_QBH = 4 +} VLANType; + +/* structure defines */ +typedef struct IPV4_Prop { + char *ip; + char *ip_mask; +} IPV4_Prop; + +typedef struct BR_Prop { + char *bridge_id; + int STP; + BrType type; + char **port_names; + int port_num; +} BR_Prop; + +typedef struct Run_Prop { + long long rx_bytes; + long long tx_bytes; + EthState state; +} Run_Prop; + +typedef struct VLAN_Qos_8021q_elem { + int from; + int to; +} VLAN_Qos_8021q_elem; + +typedef struct VLAN_Qos_8021q { + VLAN_Qos_8021q_elem values[8]; + int count; +} VLAN_Qos_8021q; + +typedef struct VLAN_Prop_8021q { + int vlan_id; + int reorder_hdr; + int priv_flag; + VLAN_Qos_8021q ingress; + VLAN_Qos_8021q egress; + char *parent; +} VLAN_Prop_8021q; + +/* HP vlan standard, TBD */ +typedef struct VLAN_Prop_8021qbg { + int invalid; +} VLAN_Prop_8021qbg; + +/* Cisco and VMware vlan standard, TBD */ +typedef struct VLAN_Prop_8021qbh { + int invalid; +} VLAN_Prop_8021qbh; + +typedef struct VLAN_Prop { + int vlan_type; + union { + VLAN_Prop_8021q prop_8021q; + VLAN_Prop_8021qbg prop_8021qbg; + VLAN_Prop_8021qbh prop_8021qbh; + } props; +} VLAN_Prop; + +/* EthIface is logical devices include eth ports and bridges */ +typedef struct EthIface { + char *name; + char *dep_ifname; /* parent dev name */ + char *attach_bridge; /* bridge the iface is attached to */ + char *mac; + EthType eth_type; + Run_Prop run_prop; + IPV4_Prop ipv4_prop; + /* optional properties */ + BR_Prop *pbr_prop; + VLAN_Prop *pvlan_prop; +} EthIface; + +typedef struct EthIfacesList { + EthIface *pifaces[MAX_IFACE_NUM]; + int count; +} EthIfacesList; + +typedef int (*eth_iface_filter_func)(const EthIface *piface, void *opaque); + +/* uninit functions are only called when there is resource malloc */ +DLL_PUBLIC void vlan_prop_init(VLAN_Prop *pvlan_prop, int vlan_type); +DLL_PUBLIC void vlan_prop_uninit(VLAN_Prop *pvlan_prop); + +DLL_PUBLIC void br_prop_init(BR_Prop *pbr_prop); +DLL_PUBLIC void br_prop_uninit(BR_Prop *pbr_prop); + +DLL_PUBLIC void eth_iface_print(EthIface *piface); +DLL_PUBLIC void eth_iface_init(EthIface *piface); +DLL_PUBLIC void eth_iface_add_br_prop(EthIface *piface); +DLL_PUBLIC void eth_iface_add_vlan_prop(EthIface *piface, int vlan_type); +DLL_PUBLIC void eth_iface_uninit(EthIface *piface); +DLL_PUBLIC void eth_ifaces_clear(EthIface **ppifaces, int num); + +DLL_PUBLIC void eth_ifaceslist_init(EthIfacesList *plist); +DLL_PUBLIC void eth_ifaceslist_uninit(EthIfacesList *plist); +DLL_PUBLIC void eth_ifaceslist_print(EthIfacesList *plist); + +/* this function assume dest have been uninited if it was used before*/ +DLL_PUBLIC void eth_iface_dup(EthIface *dest, const EthIface *src); + +/* see if it is refered to the same device */ +DLL_PUBLIC int eth_iface_compare(const EthIface *p1, const EthIface *p2); + +/* merge the properties that dest do not have value set, if style is set to 1, + the char* properties was moved instead of copy, safely reduce the memory + fragments, but src is modified. */ +DLL_PUBLIC void eth_iface_merge(EthIface *dest, EthIface *src, int style); + +DLL_PUBLIC int eth_iface_filter_by_ref(const EthIface *piface, void *pref); +DLL_PUBLIC int eth_iface_filter_by_refname(const EthIface *piface, void *pref); +DLL_PUBLIC int eth_iface_filter_vlans(const EthIface *piface, void *nouse); +DLL_PUBLIC int eth_iface_filter_peths(const EthIface *piface, void *nouse); + + +#endif diff --git a/libnetwork/host_network_error.h b/libnetwork/host_network_error.h new file mode 100644 index 0000000..5c38dde --- /dev/null +++ b/libnetwork/host_network_error.h @@ -0,0 +1,31 @@ +#ifndef HOST_NETWORK_ERROR_H +#define HOST_NETWORK_ERROR_H + +#define ERR_REQUEST_NOT_SUPPORT -1 + +#define ERR_COMMAND_NOT_SET -11 +#define ERR_COMMAND_PIPE_ERR -12 +#define ERR_COMMAND_NOT_SUPPORT -13 +#define ERR_COMMAND_NO_PERMISSION -14 +#define ERR_COMMAND_NO_READY -15 +#define ERR_COMMAND_PARAMETER_WRONG -16 +#define ERR_COMMAND_EXECUTION -17 + +#define ERR_LIBNETLINK -80 +#define ERR_LIBBR -90 + +#define ERR_DEVICE_EXCEED_MAXNUM -100 +#define ERR_DEVICE_EXIST -101 +#define ERR_DEVICE_NOT_EXIST -102 +#define ERR_DEVICE_ALREADY_DONE -103 +#define ERR_DEVICE_CONNECT_OTHER -104 + +#define ERR_FILE_OP_FAIL -125 +#define ERR_FILE_EMPTY -126 +#define ERR_FILE_TOO_LARGE -127 +#define ERR_FILE_CONT_TOO_LARGE -128 +#define ERR_FILE_LOCK_FAIL -129 + +#define ERR_PERSIST_NOT_REDHAT -200 + +#endif diff --git a/libnetwork/host_network_helper.c b/libnetwork/host_network_helper.c new file mode 100644 index 0000000..dc9f775 --- /dev/null +++ b/libnetwork/host_network_helper.c @@ -0,0 +1,659 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + + + +#include +#include +#include +#include +#include + +#include "host_network_helper.h" +#include "host_network_error.h" + +#define CONFIGURE_FILE_MAX_SIZE 2048 + +#define PIPE_CMD_SUFFIX " 2>&1" + +static int g_linux_version = LINUX_UNKNOWN; + +static int compare_qos_8021q(const void *p1, const void *p2) +{ + const VLAN_Qos_8021q_elem *qos1 = (VLAN_Qos_8021q_elem *)p1; + const VLAN_Qos_8021q_elem *qos2 = (VLAN_Qos_8021q_elem *)p2; + int ret = 0; + if ((qos1->from) > (qos2->from)) { + ret = 1; + } + return ret; +} + +/* it need to be checked see whether these are the conditions */ +int vlan_8021q_qos_check_valid(VLAN_Qos_8021q *pqos) +{ + int ret = 1; + int i = 0; + int last_num = -1; + if ((pqos->count < 0) || (pqos->count > 8)) { + ret = 0; + goto out; + } else if (pqos->count == 0) { + goto out; + } + qsort((void *)pqos->values, pqos->count, sizeof(VLAN_Qos_8021q_elem), + compare_qos_8021q); + + while (i < pqos->count) { + if (pqos->values[i].from == last_num) { + CU_DEBUG("error: vlan 802.1.q qos setting have same values: " + "last is %d, new is %d", last_num, pqos->values[i].from); + ret = 0; + goto out; + } + last_num = pqos->values[i].from; + if ((pqos->values[i].from < 0) || (pqos->values[i].from >= 8)) { + CU_DEBUG("error: vlan 802.1.q qos setting have outbound value: " + "from is %d.", pqos->values[i].from); + ret = 0; + goto out; + } + if ((pqos->values[i].to < 0) || (pqos->values[i].to >= 8)) { + CU_DEBUG("error: vlan 802.1.q qos setting have outbound value: " + "to is %d.", pqos->values[i].to); + ret = 0; + goto out; + } + i++; + } + + out: + return ret; +} + +int vlan_8021q_qos_str_to_num(VLAN_Qos_8021q *pqos, const char* str) +{ + int ret = 1; + char *str_line = NULL; + char *temp; + char *saveptr = NULL; + char *invalptr1, *invalptr2; + int qos_num1, qos_num2; + VLAN_Qos_8021q qos; + + if (str == NULL) { + ret = 0; + goto out; + } + if (str[0] == '\0') { + ret = 1; + pqos->count = 0; + CU_DEBUG("empty vlan 802.1.q qos string found."); + goto out; + } + str_line = SAFE_STRDUP(str); + qos.count = 0; + + temp = strtok_r(str_line, " ", &saveptr); + while (temp != NULL) { + qos_num1 = strtol(temp, &invalptr1, 10); + if (temp == invalptr1) { + ret = 0; + goto out; + } + if (*invalptr1 != ':') { + ret = 0; + goto out; + } + invalptr1++; + qos_num2 = strtol(invalptr1, &invalptr2, 10); + if (invalptr1 == invalptr2) { + ret = 0; + goto out; + } + if (*invalptr2 != '\0') { + ret = 0; + goto out; + } + if (qos.count >= 8) { + ret = 0; + CU_DEBUG("too many settings found in vlan 802.1.q qos string [%s]", + str); + goto out; + } + qos.values[qos.count].from = qos_num1; + qos.values[qos.count].to = qos_num2; + qos.count++; + temp = strtok_r(NULL, " ", &saveptr); + } + ret = vlan_8021q_qos_check_valid(&qos); + if (ret == 1) { + *pqos = qos; + } + + out: + if (ret != 1) { + CU_DEBUG("vlan 802.1.q qos string [%s] is invalid.", str); + } + SAFE_FREE(str_line); + return ret; +} + +int vlan_8021q_qos_num_to_str(char **str, const VLAN_Qos_8021q *pqos) +{ + char temp[16]; + int i; + VLAN_Qos_8021q qos = *pqos; + int ret = vlan_8021q_qos_check_valid(&qos); + if (ret != 1) { + goto out; + } + SAFE_MALLOC(*str, 64); + *str[0] = '\0'; + if (qos.count == 0) { + goto out; + } + i = 0; + snprintf(temp, sizeof(temp), "%d:%d", + qos.values[i].from, qos.values[i].to); + strcat(*str, temp); + i++; + while (i < qos.count) { + strcat(*str, " "); + snprintf(temp, sizeof(temp), "%d:%d", + qos.values[i].from, qos.values[i].to); + strcat(*str, temp); + i++; + } + + out: + return ret; +} + +int netmask_easy_to_inaddr(struct in_addr *paddr, const char* pmask) +{ + long mask_one_num = -1; + unsigned char *p; + int bitnum; + + mask_one_num = strtol(pmask, NULL, 10); + if ((mask_one_num < 0) || (mask_one_num > 32)) { + return 0; + } + + /* use network byte order */ + p = (unsigned char *)&paddr->s_addr; + memset(p, 0, 4); + while (mask_one_num > 8) { + *(p++) = 255; + mask_one_num -= 8; + } + bitnum = 7; + while (mask_one_num > 0) { + *p = *p + (1< 0) { + /* add the property */ + if ((cont_len + target_len) >= maxsize) { + CU_DEBUG("buffer is too small for the operation."); + valid_len = -1; + goto out; + } + strcat(cont, prefix); + strcat(cont, prop); + valid_len = cont_len + target_len; + } else { + /* remove the property, but it do not exist, so skip */ + } + } else { + /* the content exist in original contents */ + /* locate the end of the property */ + pprop_end = strstr(pprop_start, endchar1); + if (pprop_end == NULL) { + /* last line */ + origin_len = strlen(pprop_start); + pprop_end = cont+cont_len; + } else { + origin_len = pprop_end - pprop_start; + } + if (target_len > 0) { + /* change the property */ + /* check the bound */ + if ((cont_len + target_len - origin_len) >= maxsize) { + CU_DEBUG("buffer is too small for the operation."); + valid_len = -1; + goto out; + } + /* move contents in the tail */ + memmove(pprop_end+target_len-origin_len, pprop_end, + cont+cont_len+1-pprop_end); + /* copy the content of the new string */ + memcpy(pprop_start+prefix_len, prop, prop_len); + head_len = pprop_start - cont + prefix_len; + } else { + /* remove the property */ + /* move contents in the tail to replace original string*/ + memmove(pprop_end+target_len-origin_len, pprop_end, + cont+cont_len+1-pprop_end); + head_len = pprop_start - cont; + } + valid_len = cont_len + target_len - origin_len; + } + + out: + if (unchanged_len != NULL) { + *unchanged_len = head_len; + } + return valid_len; +} + +int configure_file_replace_attr(const char *path, const char *prefix, + const char *prop) +{ + int fd = -1; + int fop_ret; + struct stat s; + struct flock lock; + int lock_state = -1; + char *cont = NULL; + char *pbuff; + int write_len; + int cont_len_update; + int cont_len_unchanged; + int ret = 0; + + if ((prefix == NULL) || (*prefix == '\0')) { + CU_DEBUG("no prefix for property set, could not replace the content."); + goto out; + } + + fd = open(path, O_RDWR, 0644); + if (fd < 0) { + CU_DEBUG("Unable to open [%s], it does not exist.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock_state = fcntl(fd, F_SETLK, &lock); + if (lock_state < 0) { + CU_DEBUG("Failed to lock file [%s], it may be locked by other.", path); + ret = ERR_FILE_LOCK_FAIL; + goto out; + } + + fstat(fd, &s); + if (s.st_size == 0) { + CU_DEBUG("file [%s] is empty, will not replace attr for it.", path); + ret = ERR_FILE_EMPTY; + goto out; + } else if (s.st_size >= CONFIGURE_FILE_MAX_SIZE) { + CU_DEBUG("file [%s] is too large, " + "it have %lld bytes, will not read it.", + path, (long long)s.st_size); + ret = ERR_FILE_TOO_LARGE; + goto out; + } + + SAFE_MALLOC(cont, CONFIGURE_FILE_MAX_SIZE); + lseek(fd, 0, SEEK_SET); + fop_ret = read(fd, cont, s.st_size); + cont[s.st_size] = '\0'; + cont_len_update = replace_prop_str(cont, CONFIGURE_FILE_MAX_SIZE, + prefix, prop, &cont_len_unchanged); + if (cont_len_update < 0) { + CU_DEBUG("file [%s] is too big to expand it with [%s%s].", + path, prefix, prop); + ret = ERR_FILE_TOO_LARGE; + goto out; + } else if (cont_len_update == 0) { + CU_DEBUG("the contents was not changed, do not need update it"); + ret = 1; + goto out; + } else { + if (ftruncate(fd, cont_len_unchanged) != 0) { + CU_DEBUG("file [%s] Unable to truncate it", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + write_len = cont_len_update-cont_len_unchanged; + if (write_len > 0) { + lseek(fd, cont_len_unchanged, SEEK_SET); + CU_DEBUG("writing file [%s] for %d bytes with offset %d," + " cont is :\n%s\n", + path, write_len, cont_len_unchanged, cont); + pbuff = cont+cont_len_unchanged; + fop_ret = write(fd, pbuff, write_len); + } + } + ret = 1; + + out: + if (fd >= 0) { + if (lock_state >= 0) { + lock.l_type = F_UNLCK; + fcntl(fd, F_SETLK, &lock); + } + close(fd); + } + SAFE_FREE(cont); + return ret; +} + +int configure_file_update(const char *path, const char *cont) +{ + int fd = -1; + int fop_ret; + struct flock lock; + int lock_state = -1; + int write_len; + int ret = 0; + + fd = open(path, O_RDWR|O_CREAT, 0644); + if (fd < 0) { + CU_DEBUG("Unable to open [%s], it does not exist.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock_state = fcntl(fd, F_SETLK, &lock); + if (lock_state < 0) { + CU_DEBUG("Failed to lock file [%s], it may be locked by other.", path); + ret = ERR_FILE_LOCK_FAIL; + goto out; + } + + if (ftruncate(fd, 0) != 0) { + CU_DEBUG("file [%s] Unable to truncate it", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + write_len = strlen(cont); + if (write_len > 0) { + lseek(fd, 0, SEEK_SET); + CU_DEBUG("writing file [%s] for %d bytes with offset 0," + " cont is :\n%s\n", + path, write_len, cont); + fop_ret = write(fd, cont, write_len); + } + ret = 1; + + out: + if (fd >= 0) { + if (lock_state >= 0) { + lock.l_type = F_UNLCK; + fcntl(fd, F_SETLK, &lock); + } + close(fd); + } + return ret; +} + +int configure_file_remove(const char *path) +{ + int fd_ret; + int ret = 0; + if (access(path, F_OK) == 0) { + CU_DEBUG("Deleting %s.", path); + fd_ret = remove(path); + if (fd_ret != 0) { + CU_DEBUG("failed to remove %s.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + } + + ret = 1; + out: + return ret; +} + +FILE *pipe_excute_command_type_read(char *cmd, const int buf_size, + const char *type, int *errno) +{ + FILE *stream = NULL; + char *suffix = PIPE_CMD_SUFFIX; + if ((strlen(cmd) + strlen(suffix)) >= buf_size) { + CU_DEBUG("cmd [%s] is too long to append the suffix", cmd); + *errno = ERR_COMMAND_NO_READY; + goto out; + } + strcat(cmd, suffix); + CU_DEBUG("excuting readonly cmd [%s].", cmd); + stream = popen(cmd, type); + if (stream == NULL) { + CU_DEBUG("Failed to open pipe to run command"); + *errno = ERR_COMMAND_PIPE_ERR; + } + +out: + return stream; +} + +FILE *pipe_excute_command_type_write(char *cmd, const int buf_size, + const char *type, int *errno) +{ + FILE *stream = NULL; + char *suffix = PIPE_CMD_SUFFIX; + if ((strlen(cmd) + strlen(suffix)) >= buf_size) { + CU_DEBUG("cmd [%s] is too long to append the suffix", cmd); + *errno = ERR_COMMAND_NO_READY; + goto out; + } + strcat(cmd, suffix); + CU_DEBUG("excuting system modification cmd [%s].", cmd); + stream = popen(cmd, type); + if (stream == NULL) { + CU_DEBUG("Failed to open pipe to run command"); + *errno = ERR_COMMAND_PIPE_ERR; + } + usleep(10000); + +out: + return stream; +} + +int get_host_linux_version(void) +{ + FILE *stream = NULL; + char cmd[64]; + char buff[256]; + int linenum; + int errno; + + if (g_linux_version != LINUX_UNKNOWN) { + goto out; + } + + cmd[0] = '\0'; + strcat(cmd, "lsb_release -a"); + stream = pipe_excute_command_type_read(cmd, sizeof(cmd), "r", &errno); + if (stream == NULL) { + goto out; + } + + linenum = -1; + g_linux_version = LINUX_OTHER; + while (fgets(buff, 256, stream) != NULL) { + linenum++; + if (linenum == 0) { + if (NULL == strstr(buff, "LSB")) { + CU_DEBUG("ERR: unable to get linux distribution version."); + g_linux_version = LINUX_FAIL_TO_GET; + } + } + if ((NULL != strstr(buff, "Red Hat")) || + (NULL != strstr(buff, "RedHat"))) { + g_linux_version = LINUX_REDHAT; + break; + } + } + + out: + if (stream != NULL) { + pclose(stream); + } + return g_linux_version; +} + +char *translate_error_no(int errno) +{ + char *ret = NULL; + switch (errno) { + case ERR_REQUEST_NOT_SUPPORT: + ret = "request is not supported now"; + break; + + case ERR_COMMAND_NOT_SET: + ret = "command is not set."; + break; + case ERR_COMMAND_PIPE_ERR: + ret = "failed in creating pipe to execute the command."; + break; + case ERR_COMMAND_NOT_SUPPORT: + ret = "command is not found, check u environment."; + break; + case ERR_COMMAND_NO_PERMISSION: + ret = "not enough authority to execute the command."; + break; + case ERR_COMMAND_NO_READY: + ret = "failed to build up the command line, check your input, " + "maybe it is too long."; + break; + case ERR_COMMAND_PARAMETER_WRONG: + ret = "got invalid paramenter, check your input."; + break; + case ERR_COMMAND_EXECUTION: + ret = "error happened in the excution of command."; + break; + + case ERR_DEVICE_EXCEED_MAXNUM: + ret = "too many devices found or set, check the environment."; + break; + case ERR_DEVICE_EXIST: + ret = "device already exist, can not execute the command."; + break; + case ERR_DEVICE_NOT_EXIST: + ret = "device do not exist, can not execute the command."; + break; + case ERR_DEVICE_ALREADY_DONE: + ret = "the operation you want have been done before, " + "will not do it again."; + break; + case ERR_DEVICE_CONNECT_OTHER: + ret = "the device you want to connect have been connect to another" + " device, can't change it directly."; + break; + + case ERR_FILE_OP_FAIL: + ret = "failed in accessing the file."; + break; + case ERR_FILE_EMPTY: + ret = "the file it want is empty."; + break; + case ERR_FILE_TOO_LARGE: + ret = "the file it want is too large."; + break; + case ERR_FILE_CONT_TOO_LARGE: + ret = "the content it want to combine to file is too large."; + break; + case ERR_FILE_LOCK_FAIL: + ret = "failed in locking the file, " + "check if other process is using it."; + break; + + case ERR_PERSIST_NOT_REDHAT: + ret = "host is not a RedHat distribution, can't persist the " + "configuration, it would not take effect after host is " + "rebooted. Other version would be supported in the future. " + "If you are sure host is RedHat, make sure command " + " could work."; + break; + + default: + ret = "internal error."; + break; + } + return ret; +} diff --git a/libnetwork/host_network_helper.h b/libnetwork/host_network_helper.h new file mode 100644 index 0000000..4170366 --- /dev/null +++ b/libnetwork/host_network_helper.h @@ -0,0 +1,202 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + + +#ifndef HOST_NETWORK_HELPER_H +#define HOST_NETWORK_HELPER_H + +#include +#include +#include + +#include "dll_magic.h" +#include "host_network_basic.h" + +#ifdef TESTLIB +#include "TestDefines.h" +#else +#include +#endif + +#define LINUX_FAIL_TO_GET -2 +#define LINUX_UNKNOWN -1 +#define LINUX_OTHER 0 +#define LINUX_REDHAT 1 + +#define CMD_DEBUG_LEVEL 2 + +/* macro functions */ +#define CMD_DEBUG(lvl, fmt, args...) do { \ + if (CMD_DEBUG_LEVEL && (lvl) <= CMD_DEBUG_LEVEL) { \ + debug_print(fmt, ##args); \ + } \ +} while (0) + +#define SAFE_MALLOC(p, size) \ +{ \ + (p) = malloc((size)); \ + if ((p) == NULL) { \ + CU_DEBUG("malloc failed."); \ + } \ +} + +#define SAFE_CALLOC(p, nmen, size) \ +{ \ + (p) = calloc((nmen), (size)); \ + if ((p) == NULL) { \ + CU_DEBUG("calloc failed."); \ + } \ +} + +#define SAFE_FREE(p) {free(p); (p) = NULL; } + + +/* Macro used to compare two char*, it would skip if ref is NULL. It would + only set the result when src != ref, user need to set the result to 1 by + default before use the macro. If not set, the it could be used to do + check multi times in "one fail all die" mode. Empty lines is the place + where result should be set to 1. */ +#define CHARS_COMPARE_BY_REF(src, ref, result) do { \ + if ((ref) == NULL) { \ + ; \ + } else { \ + if ((src) == NULL) { \ + (result) = 0; \ + } else { \ + if (0 == strcmp((src), (ref))) { \ + ; \ + } else { \ + (result) = 0; \ + } \ + } \ + } \ +} while (0) + +/* ignore case version */ +#define CHARS_COMPARE_CASE_BY_REF(src, ref, result) do { \ + if ((ref) == NULL) { \ + ; \ + } else { \ + if ((src) == NULL) { \ + (result) = 0; \ + } else { \ + if (0 == strcasecmp((src), (ref))) { \ + ; \ + } else { \ + (result) = 0; \ + } \ + } \ + } \ +} while (0) + +/* compare the value if ref != default */ +#define NUM_COMPARE_BY_REF(src, ref, result, default) do { \ + if ((ref) == (default)) { \ + ; \ + } else { \ + if ((src) == (ref)) { \ + ; \ + } else { \ + result = 0; \ + } \ + } \ +} while (0) + +/* merge the char* string to dest, only when dest == NULL */ +#define CHARS_MERGE_NORMAL(dest, src) do { \ + if (((dest) == NULL) && ((src) != NULL)) { \ + (dest) = strdup((src)); \ + } \ +} while (0) + +/* merge the char* string to dest, only when dest == NULL, + pointer is moved instead of strdup */ +#define CHARS_MERGE_MOVE(dest, src) do { \ + if (((dest) == NULL) && ((src) != NULL)) { \ + (dest) = (src); \ + (src) = NULL; \ + } \ +} while (0) + +/* merge the value, only when dest == default */ +#define NUM_MERGE(dest, src, default) do { \ + if ((dest) == (default)) { \ + (dest) = (src); \ + } \ +} while (0) + +/* this macro may cause "p" to be excuted twice if it is a function */ +#define SAFE_STRDUP(p) (p) == NULL ? NULL : strdup(p); + +/* this macro make sure "src" to be excuted once if it is function, so it is + safe for functions that have state logged, such as "strtok" */ +#define SAFE_STRDUP_WITH_FUNC(dest, src, iter) do { \ + (iter) = (src); \ + if ((iter) == NULL) { \ + (dest) = NULL; \ + } else { \ + (dest) = strdup((iter)); \ + } \ +} while (0) + +/* array version of SAFE_STRDUP, dest and src are char**. */ +#define SAFE_PSTR_ARRAY_DUP(ppdest, dest_num, ppsrc, src_num, iter) do { \ + (dest_num) = (src_num); \ + (ppdest) = NULL; \ + if (((ppsrc) != NULL) && ((src_num) > 0)) { \ + SAFE_CALLOC((ppdest), (src_num), sizeof(char *)); \ + (iter) = 0; \ + while ((iter) < (src_num)) { \ + *((ppdest)+(iter)) = SAFE_STRDUP(*((ppsrc)+(iter))); \ + (iter)++; \ + } \ + } \ +} while (0) + +/* functions */ +/* this function convert ip mask "24" in "192.1.0.9/24" to real mask num as + 255.255.255.0 */ +int netmask_easy_to_inaddr(struct in_addr *paddr, const char *pmask); + +/* this function would sort the pqos and check its values. */ +int vlan_8021q_qos_check_valid(VLAN_Qos_8021q *pqos); + +/* converting qos string of 802.1.Q, it should be as "0:0 1:0 2:0" */ +DLL_PUBLIC int vlan_8021q_qos_str_to_num(VLAN_Qos_8021q *pqos, const char *str); +DLL_PUBLIC int vlan_8021q_qos_num_to_str(char **str, const VLAN_Qos_8021q *pqos); + +/* following functions would return FILE popened, so it need pclose later, + cmd would be appended so it must be writable. */ +FILE *pipe_excute_command_type_read(char *cmd, const int buf_size, + const char *type, int *errno); +FILE *pipe_excute_command_type_write(char *cmd, const int buf_size, + const char *type, int *errno); + +/* following functions would return string by malloc, so it need free later */ +char *strtok_onetime(const char *str, const char *delim); +char *combine_file_name(const char *prefix, const char *name); + +/* write the configuration file */ +int configure_file_update(const char *path, const char *cont); +/* remove the configuration file */ +int configure_file_remove(const char *path); +/* replace one attribute, the file have format with one line for one propety */ +int configure_file_replace_attr(const char *path, const char *prefix, + const char *prop); + +/* check host linux version */ +int get_host_linux_version(void); + +/* err message number to char* */ +char *translate_error_no(int errno); + +#endif diff --git a/libnetwork/host_network_implement_OSAPI.c b/libnetwork/host_network_implement_OSAPI.c new file mode 100644 index 0000000..24b382e --- /dev/null +++ b/libnetwork/host_network_implement_OSAPI.c @@ -0,0 +1,453 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "libbridge/libbridge.h" + +#include "host_network_implement_OSAPI.h" +#include "host_network_helper.h" +#include "host_network_error.h" + +/* macro defines */ +#define LN_PRINT_LEVEL 3 + +struct nl_add2list_param { + EthIfacesList *plist; + struct nl_cache *cache; +} ; + +/* the bridge seems have 0 value when it is up , so adjust the value, + and found out which are physical cards */ +static int host_iface_adjust(EthIface *piface) +{ + if ((piface->eth_type & ETH_TYPE_ETHER_ANY) && + (piface->eth_type & ETH_TYPE_ETHER_SUB_BRIDGE)) { + if (piface->run_prop.state == ETH_STATE_UNKNOWN) { + piface->run_prop.state = ETH_STATE_UP; + } + } + if (1 == eth_iface_filter_peths(piface, NULL)) { + piface->eth_type |= (ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_PHYSICAL); + } + return 1; +} + +static void find_iface_attached_bridge(EthIfacesList *peth_list, EthIface *pbr) +{ + int i, j; + char *name_on_br, *name_iface; + if (pbr->pbr_prop == NULL) { + return; + } + i = 0; + while (i < pbr->pbr_prop->port_num) { + name_on_br = pbr->pbr_prop->port_names[i]; + j = 0; + while (j < peth_list->count) { + name_iface = peth_list->pifaces[j]->name; + if (0 == strcmp(name_on_br, name_iface)) { + if (peth_list->pifaces[j]->attach_bridge == NULL) { + peth_list->pifaces[j]->attach_bridge = + SAFE_STRDUP(pbr->name); + } + break; + } + j++; + } + i++; + } +} + +/* assuming that one peth would be attached to at most 1 bridge */ +static void merge_eth_list_for_bridge(EthIfacesList *peth_list, + EthIfacesList *pbr_list, + int flag) +{ + int i, j; + i = 0; + while (i < pbr_list->count) { + find_iface_attached_bridge(peth_list, pbr_list->pifaces[i]); + j = 0; + while (j < peth_list->count) { + if (1 == eth_iface_compare(peth_list->pifaces[j], + pbr_list->pifaces[i])) { + /* found the matched device, merge them */ + eth_iface_merge(peth_list->pifaces[j], + pbr_list->pifaces[i], flag); + break; + } + j++; + } + i++; + } + return; +} + +static int br_addports_func(const char *brname, const char *port, void *opaque) +{ + BR_Prop *pbr; + int ret = 0; + + pbr = (BR_Prop *)opaque; + + if (port != NULL) { + /* adding the port */ + if (pbr->port_names == NULL) { + SAFE_CALLOC(pbr->port_names, + MAX_IFACE_NUM, sizeof(char *)); + pbr->port_num = 0; + } + if (pbr->port_num >= MAX_IFACE_NUM) { + CU_DEBUG("bridge [%s] have too much eth attached!", brname); + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + + pbr->port_names[pbr->port_num] = SAFE_STRDUP(port); + pbr->port_num++; + } + + out: + return ret; +} + +static int br_add2list_func(const char *name, void *opaque) +{ + int count; + EthIfacesList *plist; + EthIface tcard; + BR_Prop *pbr; + struct bridge_info binfo; + int ret = 0; + + plist = (EthIfacesList *)opaque; + eth_iface_init(&tcard); + + tcard.eth_type = ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_BRIDGE; + tcard.name = SAFE_STRDUP(name); + + SAFE_MALLOC(pbr, sizeof(BR_Prop)); + br_prop_init(pbr); + tcard.pbr_prop = pbr; + + if (0 == br_get_bridge_info(name, &binfo)) { + pbr->STP = binfo.stp_enabled; + } else { + CU_DEBUG("failed to get bridge_info for %s.", name); + } + count = br_foreach_port(name, br_addports_func, pbr); + + /* put result to list */ + if (plist->count >= MAX_IFACE_NUM) { + CU_DEBUG("too much device found."); + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + SAFE_MALLOC(plist->pifaces[plist->count], sizeof(EthIface)); + eth_iface_dup(plist->pifaces[plist->count], &tcard); + plist->count++; + + out: + eth_iface_uninit(&tcard); + return ret; +} + +static int get_host_eth_ifaces_osapi_bridge(EthIfacesList *plist) +{ + int count; + int ret = 0, libret; + + libret = br_init(); + if (libret != 0) { + ret = ERR_LIBBR; + CU_DEBUG("erro in init the libbridge, errno is %d.", libret); + goto out; + } + + count = br_foreach_bridge(br_add2list_func, plist); + + if (plist->count >= MAX_IFACE_NUM) { + CU_DEBUG("too much device found."); + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + + ret = 1; + + out: + br_shutdown(); + return ret; +} + +static void ln_link_print(struct rtnl_link *link) +{ + char *name, *qdisk, *type; + const char *ifalias; + int ifindex, flags, mtu, txqlen, family, arptype, getlink, master, operstate, linkmode; + uint32_t num_vf = 0; + int ret, i; + int vlanid, vlanflag, egress_num = 0; + uint32_t *ingress_map; + struct vlan_map *egress_map; + + qdisk = rtnl_link_get_qdisc(link); + name = rtnl_link_get_name(link); + flags = rtnl_link_get_flags(link); + mtu = rtnl_link_get_mtu(link); + txqlen = rtnl_link_get_txqlen(link); + ifindex = rtnl_link_get_ifindex(link); + family = rtnl_link_get_family(link); + arptype = rtnl_link_get_arptype(link); + getlink = rtnl_link_get_link(link); + master = rtnl_link_get_master(link); + operstate = rtnl_link_get_operstate(link); + linkmode = rtnl_link_get_linkmode(link); + ifalias = rtnl_link_get_ifalias(link); + ret = rtnl_link_get_num_vf(link, &num_vf); + + type = rtnl_link_get_type(link); + CMD_DEBUG(1, "link name %s, alias %s, qdisk %s, type %s,\n" + "--ifindex 0x%x, flags 0x%x, mtu 0x%x, txqlen 0x%x, family 0x%x, arptype 0x%x,\n" + "--getlink 0x%x, master 0x%x, operstate 0x%x, linkmode 0x%x, vf_ret %d with num_vf 0x%x.\n", + name, ifalias, qdisk, type, + ifindex, flags, mtu, txqlen, family, arptype, + getlink, master, operstate, linkmode, ret, num_vf); + + if (rtnl_link_is_vlan(link)) { + vlanid = rtnl_link_vlan_get_id(link); + vlanflag = rtnl_link_vlan_get_flags(link); + ingress_map = rtnl_link_vlan_get_ingress_map(link); + egress_map = rtnl_link_vlan_get_egress_map(link, &egress_num); + CMD_DEBUG(1, "--vlan properties:\n" + "----id %d, vlanflag 0x%x.", + vlanid, vlanflag); + CMD_DEBUG(1, "\n----ingress: "); + if (ingress_map != NULL) { + for (i = 0; i <= VLAN_PRIO_MAX; i++) { + CMD_DEBUG(1, "0x%x, ", ingress_map[i]); + } + } + CMD_DEBUG(1, "\n----egress: "); + if (egress_map != NULL) { + i = 0; + while (i < egress_num) { + CMD_DEBUG(1, "[%d %d], ", egress_map[i].vm_from, egress_map[i].vm_to); + i++; + } + } + CMD_DEBUG(1, "\n"); + } +} + +static void nl_add2list_func(struct nl_object *obj, void *opaque) +{ + struct rtnl_link *link; + struct nl_cache *cache; + struct rtnl_link *ll; + struct nl_addr *addr; + uint32_t *ingress_map; + int egress_num = 0; + struct vlan_map *egress_map; + EthIfacesList *plist; + EthIface tcard; + VLAN_Prop_8021q *pprop_8021q; + char buf[128]; + int t, i; + + struct nl_add2list_param *pparam = (struct nl_add2list_param *)opaque; + plist = pparam->plist; + cache = pparam->cache; + link = (struct rtnl_link *)obj; + + if (CMD_DEBUG_LEVEL && (LN_PRINT_LEVEL) <= CMD_DEBUG_LEVEL) { + ln_link_print(link); + } + + /* get properties */ + eth_iface_init(&tcard); + + /* get name */ + tcard.name = SAFE_STRDUP(rtnl_link_get_name(link)); + + /* get parent */ + t = rtnl_link_get_link(link); + if (t > 0) { + ll = rtnl_link_get(cache, t); + if (ll == NULL) { + CU_DEBUG("failed to find interface with index %d.", t); + goto out; + } + tcard.dep_ifname = SAFE_STRDUP(rtnl_link_get_name(ll)); + rtnl_link_put(ll); + } + + /* get mac */ + addr =rtnl_link_get_addr(link); + if (addr && !nl_addr_iszero(addr)) { + nl_addr2str(addr, buf, sizeof(buf)); + tcard.mac = SAFE_STRDUP(buf); + } + + /* get main type */ + t = rtnl_link_get_arptype(link); + if (t == ARPHRD_ETHER) { + tcard.eth_type = ETH_TYPE_ETHER_ANY; + } else { + tcard.eth_type = ETH_TYPE_OTHER; + } + + /* get vlan */ + if (rtnl_link_is_vlan(link)) { + SAFE_MALLOC(tcard.pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(tcard.pvlan_prop, VLAN_TYPE_802_1_Q); + pprop_8021q = &(tcard.pvlan_prop->props.prop_8021q); + tcard.eth_type |= ETH_TYPE_ETHER_SUB_VLAN; + pprop_8021q->vlan_id = rtnl_link_vlan_get_id(link); + pprop_8021q->reorder_hdr = (rtnl_link_vlan_get_flags(link) & + VLAN_FLAG_REORDER_HDR); + /* at any time parent of vlan8021.q is just what it depends on */ + pprop_8021q->parent = SAFE_STRDUP(tcard.dep_ifname); + ingress_map = rtnl_link_vlan_get_ingress_map(link); + egress_map = rtnl_link_vlan_get_egress_map(link, &egress_num); + if (ingress_map != NULL) { + for (i = 0; i <= VLAN_PRIO_MAX; i++) { + pprop_8021q->ingress.values[i].from = i; + pprop_8021q->ingress.values[i].to = ingress_map[i]; + } + pprop_8021q->ingress.count = VLAN_PRIO_MAX; + i = 0; + while (i < egress_num) { + pprop_8021q->egress.values[i].from = egress_map[i].vm_from; + pprop_8021q->egress.values[i].to = egress_map[i].vm_to; + i++; + } + pprop_8021q->egress.count = egress_num; + } + } + + + /* put result to list */ + if (plist->count >= MAX_IFACE_NUM) { + CU_DEBUG("too much device found."); + goto out; + } + SAFE_MALLOC(plist->pifaces[plist->count], sizeof(EthIface)); + eth_iface_dup(plist->pifaces[plist->count], &tcard); + plist->count++; + + out: + eth_iface_uninit(&tcard); +} + +static int get_host_eth_ifaces_osapi_netlink(EthIfacesList *plist) +{ + struct nl_sock *sk = NULL; + struct nl_cache *cache = NULL; + int ret, rtnl_ret; + struct nl_add2list_param param; + + sk = nl_socket_alloc(); + nl_connect(sk, NETLINK_ROUTE); + + rtnl_ret = rtnl_link_alloc_cache(sk, AF_UNSPEC, &cache); + if (rtnl_ret < 0) { + CU_DEBUG("error in talking to kernel, return %d.\n", rtnl_ret); + ret = ERR_LIBNETLINK; + } + + param.plist = plist; + param.cache = cache; + nl_cache_foreach(cache, nl_add2list_func, ¶m); + if (plist->count >= MAX_IFACE_NUM) { + CU_DEBUG("too much device found."); + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + + ret = 1; + + out: + nl_cache_free(cache); + nl_socket_free(sk); + + return ret; +} + +int get_host_eth_ifaces_osapi(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque) +{ + int retvalue; + EthIfacesList *ifaces1, *ifaces2; + int i; + int filter_ret; + int count = 0; + SAFE_MALLOC(ifaces1, sizeof(EthIfacesList)); + SAFE_MALLOC(ifaces2, sizeof(EthIfacesList)); + eth_ifaceslist_init(ifaces1); + eth_ifaceslist_init(ifaces2); + + retvalue = get_host_eth_ifaces_osapi_netlink(ifaces1); + if (retvalue != 1) { + goto out; + } + + retvalue = get_host_eth_ifaces_osapi_bridge(ifaces2); + if (retvalue != 1) { + goto out; + } + /* merge the information */ + merge_eth_list_for_bridge(ifaces1, ifaces2, 1); + eth_ifaceslist_uninit(ifaces2); + + /* filter the result */ + i = 0; + while (i < ifaces1->count) { + /* see if the result need to be put to the list */ + filter_ret = 1; + if (filter_func != NULL) { + filter_ret = filter_func(ifaces1->pifaces[i], filter_opaque); + } + if (filter_ret == 1) { + if (count >= MAX_IFACE_NUM) { + retvalue = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + host_iface_adjust(ifaces1->pifaces[i]); + plist->pifaces[count] = ifaces1->pifaces[i]; + ifaces1->pifaces[i] = NULL; + count++; + } + i++; + } + + out: + eth_ifaceslist_uninit(ifaces1); + SAFE_FREE(ifaces1); + eth_ifaceslist_uninit(ifaces2); + SAFE_FREE(ifaces2); + plist->count = count; + return retvalue; +} diff --git a/libnetwork/host_network_implement_OSAPI.h b/libnetwork/host_network_implement_OSAPI.h new file mode 100644 index 0000000..f72bf52 --- /dev/null +++ b/libnetwork/host_network_implement_OSAPI.h @@ -0,0 +1,21 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#ifndef HOST_NETWORK_IMPLEMENT_OSAPI_H +#define HOST_NETWORK_IMPLEMENT_OSAPI_H + +#include "host_network_basic.h" + +int get_host_eth_ifaces_osapi(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque); + +#endif diff --git a/libnetwork/libnetwork_test.c b/libnetwork/libnetwork_test.c new file mode 100644 index 0000000..e8168b8 --- /dev/null +++ b/libnetwork/libnetwork_test.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "host_network_API.h" + +static long print_and_ret_time_stamp(void) +{ + struct timeval tv; + long ret; + gettimeofday(&tv, NULL); + ret = tv.tv_sec*1000+ tv.tv_usec/1000; + printf("time is [%ld] ms.", ret); + return ret; +} + +int main(int argc, char **argv) +{ + EthIfacesList ifaces_list; + EthIface iface_ref,iface_br,iface_vlan; + int comp_ret = 0; + int persist_flag = 1; + long timestart, timeend; + + + printf("executing the program with persist flag %d.\n", persist_flag); + comp_ret = 0; + + eth_ifaceslist_init(&ifaces_list); + eth_iface_init(&iface_ref); + eth_iface_init(&iface_br); + eth_iface_init(&iface_vlan); + + eth_iface_add_br_prop(&iface_br); + eth_iface_add_vlan_prop(&iface_vlan, VLAN_TYPE_802_1_Q); + iface_br.eth_type = ETH_TYPE_ETHER_SUB_BRIDGE | ETH_TYPE_ETHER_ANY; + iface_vlan.eth_type = ETH_TYPE_ETHER_SUB_VLAN | ETH_TYPE_ETHER_ANY; + + //iface_ref.name = SAFE_STRDUP("eth1.100"); + iface_ref.eth_type = ETH_TYPE_ETHER_SUB_BRIDGE | ETH_TYPE_ETHER_ANY; + + iface_br.name = SAFE_STRDUP("test_br"); + iface_vlan.name = SAFE_STRDUP("eth0.1000"); + + iface_br.pbr_prop->STP = 1; + + iface_vlan.pvlan_prop->vlan_type = VLAN_TYPE_802_1_Q; + iface_vlan.pvlan_prop->props.prop_8021q.parent = SAFE_STRDUP("eth0"); + iface_vlan.pvlan_prop->props.prop_8021q.vlan_id = 1000; + iface_vlan.pvlan_prop->props.prop_8021q.reorder_hdr = 0; + iface_vlan.pvlan_prop->props.prop_8021q.ingress.count = 1; + iface_vlan.pvlan_prop->props.prop_8021q.ingress.values[0].from = 2; + iface_vlan.pvlan_prop->props.prop_8021q.ingress.values[0].to = 3; + iface_vlan.pvlan_prop->props.prop_8021q.egress.count = 1; + iface_vlan.pvlan_prop->props.prop_8021q.egress.values[0].from = 4; + iface_vlan.pvlan_prop->props.prop_8021q.egress.values[0].to = 6; + + timestart = print_and_ret_time_stamp(); + printf(" start list the host ifaces.\n"); + + get_host_ifaces(&ifaces_list, NULL, NULL); + //get_host_ifaces(&ifaces_list, eth_iface_filter_by_ref, &iface_ref); + //get_host_ifaces(&ifaces_list, eth_iface_filter_vlans, NULL); + //get_host_ifaces(&ifaces_list, eth_iface_filter_peths, NULL); + + timeend = print_and_ret_time_stamp(); + printf(" end list the host ifaces, cost [%ld]ms.\n", timeend-timestart); + + eth_ifaceslist_print(&ifaces_list); + eth_ifaceslist_uninit(&ifaces_list); + + eth_iface_uninit(&iface_ref); + eth_iface_uninit(&iface_br); + eth_iface_uninit(&iface_vlan); + + return 0; +} -- 1.7.6 From xiawenc at linux.vnet.ibm.com Thu Jan 12 09:46:51 2012 From: xiawenc at linux.vnet.ibm.com (Wayne Xia) Date: Thu, 12 Jan 2012 17:46:51 +0800 Subject: [Libvirt-cim] [V3 PATCH 07/10] CIM model - VESS In-Reply-To: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1326361614-18674-8-git-send-email-xiawenc@linux.vnet.ibm.com> According to DSP1097, Virtual switch is modeled similar to virtual computer system. This patch consider two device as switch system: pyhical network card and bridge. Signed-off-by: Wayne Xia --- schema/VirtualEthernetSwitchSystem.mof | 10 + schema/VirtualEthernetSwitchSystem.registration | 3 + src/Virt_VirtualEthernetSwitchSystem.c | 477 +++++++++++++++++++++++ src/Virt_VirtualEthernetSwitchSystem.h | 52 +++ 4 files changed, 542 insertions(+), 0 deletions(-) create mode 100644 schema/VirtualEthernetSwitchSystem.mof create mode 100644 schema/VirtualEthernetSwitchSystem.registration create mode 100644 src/Virt_VirtualEthernetSwitchSystem.c create mode 100644 src/Virt_VirtualEthernetSwitchSystem.h diff --git a/schema/VirtualEthernetSwitchSystem.mof b/schema/VirtualEthernetSwitchSystem.mof new file mode 100644 index 0000000..5c016fd --- /dev/null +++ b/schema/VirtualEthernetSwitchSystem.mof @@ -0,0 +1,10 @@ +// Copyright IBM Corp. 2011 +[Description ( + "A class derived from CIM_ComputerSystem to represent " + "the Virtual Bridge on the host."), + Provider("cmpi::Virt_VirtualEthernetSwitchSystem") +] +class Net_VirtualEthernetSwitchSystem : CIM_ComputerSystem +{ + +}; diff --git a/schema/VirtualEthernetSwitchSystem.registration b/schema/VirtualEthernetSwitchSystem.registration new file mode 100644 index 0000000..4cd6bf4 --- /dev/null +++ b/schema/VirtualEthernetSwitchSystem.registration @@ -0,0 +1,3 @@ +# Copyright IBM Corp. 2007 +# Classname Namespace ProviderName ProviderModule ProviderTypes +Net_VirtualEthernetSwitchSystem root/virt Virt_VirtualEthernetSwitchSystem Virt_VirtualEthernetSwitchSystem instance method diff --git a/src/Virt_VirtualEthernetSwitchSystem.c b/src/Virt_VirtualEthernetSwitchSystem.c new file mode 100644 index 0000000..1816771 --- /dev/null +++ b/src/Virt_VirtualEthernetSwitchSystem.c @@ -0,0 +1,477 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "Virt_VirtualEthernetSwitchSystem.h" +#include "device_parsing.h" +#include "network_model_helper.h" + +static const CMPIBroker *_BROKER; + +static int set_primary_for_switch(const CMPIBroker *broker, EthIface *piface, + CMPIInstance *instance) +{ + char *name; + uint16_t dedicated; + CMPIArray *array; + CMPIStatus s = {CMPI_RC_OK, NULL}; + + if (piface->name == NULL) { + return 0; + } + + name = get_switch_name_from_iface(piface->name); + CMSetProperty(instance, "Name", + (CMPIValue *)name, CMPI_chars); + CMSetProperty(instance, "ElementName", + (CMPIValue *)name, CMPI_chars); + SAFE_FREE(name); + + array = CMNewArray(broker, 1, CMPI_uint16, &s); + if ((s.rc != CMPI_RC_OK) || (CMIsNullObject(array))) { + return 0; + } + dedicated = CIM_NUM_SWITCH_DEDICATED; + CMSetArrayElementAt(array, 0, &dedicated, CMPI_uint16); + CMSetProperty(instance, "Dedicated", + (CMPIValue *)&array, CMPI_uint16A); + + return 1; +} + +static int set_secondary_for_switch(const CMPIBroker *broker, EthIface *piface, + CMPIInstance *instance) +{ + int state; + if (piface->run_prop.state == ETH_STATE_DOWN) { + state = CIM_STATE_DISABLED; + } else if (piface->run_prop.state == ETH_STATE_UP) { + state = CIM_STATE_ENABLED; + } else { + state = CIM_STATE_UNKNOWN; + } + CMSetProperty(instance, "EnabledState", + (CMPIValue *)&state, CMPI_uint16); + CMSetProperty(instance, "RequestedState", + (CMPIValue *)&state, CMPI_uint16); + + return 1; +} + +/* Populate an instance with information from a switch */ +static CMPIStatus set_properties(const CMPIBroker *broker, + EthIface *piface, + const char *prefix, + CMPIInstance *instance) +{ + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; + char *errstr; + + if (!set_primary_for_switch(broker, piface, instance)) { + errstr = "failed to set primary properties for instance."; + CU_DEBUG("%s, iface name %s.", errstr, piface->name); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + if (!set_secondary_for_switch(broker, piface, instance)) { + errstr = "failed to set secondary properties for instance."; + CU_DEBUG("%s, iface name %s.", errstr, piface->name); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + cu_statusf(broker, &s, + CMPI_RC_OK, + ""); + + out: + return s; +} + +static CMPIStatus instance_from_switch(const CMPIBroker *broker, + const CMPIObjectPath *reference, + EthIface *piface, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + + inst = get_typed_instance(broker, + NETWORK_CLASS_PREFIX, + "VirtualEthernetSwitchSystem", + NAMESPACE(reference)); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to init VirtualEthernetSwitchSystem instance"); + goto out; + } + + s = set_properties(broker, + piface, + NETWORK_CLASS_PREFIX, + inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + *_inst = inst; + + out: + return s; +} + +CMPIStatus enum_switches(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const CMPIResult *results, + bool names_only) +{ + struct inst_list list; + CMPIStatus s = {CMPI_RC_OK, NULL}; + EthIfacesList ifaces_list; + int ret, i; + char *errstr; + + inst_list_init(&list); + eth_ifaceslist_init(&ifaces_list); +CU_DEBUG("##enum switch before"); + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_cim_switch, NULL); +CU_DEBUG("##enum switch after"); + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + i = 0; + while (i < ifaces_list.count) { + CMPIInstance *inst = NULL; + + s = instance_from_switch(broker, + reference, + ifaces_list.pifaces[i], + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(&list, inst); + i++; + } + + if (names_only) { + cu_return_instance_names(results, &list); + } else { + cu_return_instances(results, &list); + } + + out: + inst_list_free(&list); + eth_ifaceslist_uninit(&ifaces_list); + + return s; +} + +CMPIStatus get_switch_by_name(const CMPIBroker *broker, + const char *name, + const CMPIObjectPath *reference, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *eth_name = NULL; + char *errstr; + int ret; + EthIfacesList ifaces_list; + + eth_ifaceslist_init(&ifaces_list); + + eth_name = get_iface_name_from_switch(name); + if (eth_name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to convert switch_name"); + CU_DEBUG("switch name %s failed to convert.", name); + goto out; + } + + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_cim_switch_for_name, eth_name); + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + if (ifaces_list.count != 1) { + errstr = "expected switch not found."; + CU_DEBUG("%s\n", errstr); + eth_ifaceslist_print(&ifaces_list); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + s = instance_from_switch(broker, + reference, + ifaces_list.pifaces[0], + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + eth_ifaceslist_uninit(&ifaces_list); + SAFE_FREE(eth_name); + return s; +} + +CMPIStatus get_switch_by_ref(const CMPIBroker *broker, + const CMPIObjectPath *reference, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + const char *name = NULL; + + if (cu_get_str_path(reference, "Name", &name) != CMPI_RC_OK) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "No domain name specified"); + goto out; + } + + s = get_switch_by_name(broker, name, reference, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + s = cu_validate_ref(broker, reference, inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + + return s; +} + +static CMPIStatus __state_change(const CMPIBroker *broker, + const char *name, + uint16_t state, + const CMPIObjectPath *ref) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + EthIface iface; + int iface_state; + int ret; + char *errstr; + + eth_iface_init(&iface); + iface.name = get_iface_name_from_switch(name); + if (iface.name == NULL) { + errstr = "failed to get iface name."; + CU_DEBUG("for %s, %s.", name, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + if (state == CIM_STATE_ENABLED) { + iface_state = ETH_STATE_UP; + } else if (state == CIM_STATE_DISABLED) { + iface_state = ETH_STATE_DOWN; + } else { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_SUPPORTED, + "State not supported"); + goto out; + } + + /* TBD in next patch + ret = change_state_host_iface(&iface, iface_state); */ + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + + out: + eth_iface_uninit(&iface); + return s; +} + +static CMPIStatus EnumInstanceNames(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference) +{ + return enum_switches(_BROKER, reference, results, true); +} + +static CMPIStatus EnumInstances(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const char **properties) +{ + return enum_switches(_BROKER, reference, results, false); +} + +static CMPIStatus GetInstance(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const char **properties) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + + s = get_switch_by_ref(_BROKER, reference, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + CMReturnInstance(results, inst); + + out: + return s; +} + +DEFAULT_CI(); +DEFAULT_MI(); +DEFAULT_DI(); +DEFAULT_EQ(); +DEFAULT_INST_CLEANUP(); + +static CMPIStatus state_change(CMPIMethodMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const CMPIArgs *argsin, + CMPIArgs *argsout) +{ + CMPIStatus s; + CMPIInstance *prev_inst = NULL; + uint16_t state; + int ret; + const char *name = NULL; + uint32_t rc = 1; + + ret = cu_get_u16_arg(argsin, "RequestedState", &state); + if (ret != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_INVALID_PARAMETER, + "Invalid RequestedState"); + goto out; + } + + if (cu_get_str_path(reference, "Name", &name) != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Name key not specified"); + goto out; + } + + s = get_switch_by_name(_BROKER, name, reference, &prev_inst); + if (s.rc != CMPI_RC_OK || prev_inst == NULL) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_INVALID_PARAMETER, + "Unable to get instance for guest '%s'", + name); + goto out; + } + + s = __state_change(_BROKER, name, state, reference); + + if (s.rc == CMPI_RC_OK) { + rc = 0; + } + out: + CMReturnData(results, &rc, CMPI_uint32); + + return s; +} + +STD_InstanceMIStub(, + Virt_VirtualEthernetSwitchSystem, + _BROKER, + libvirt_cim_init()); + +static struct method_handler RequestStateChange = { + .name = "RequestStateChange", + .handler = state_change, + .args = {{"RequestedState", CMPI_uint16, false}, + {"TimeoutPeriod", CMPI_dateTime, true}, + ARG_END + } +}; + +static struct method_handler *my_handlers[] = { + &RequestStateChange, + NULL +}; + +STDIM_MethodMIStub(, + Virt_VirtualEthernetSwitchSystem, + _BROKER, + libvirt_cim_init(), + my_handlers); + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/Virt_VirtualEthernetSwitchSystem.h b/src/Virt_VirtualEthernetSwitchSystem.h new file mode 100644 index 0000000..de8587b --- /dev/null +++ b/src/Virt_VirtualEthernetSwitchSystem.h @@ -0,0 +1,52 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __VIRT_VIRTUALETHERNETSWITCHSYSTEM_H +#define __VIRT_VIRTUALETHERNETSWITCHSYSTEM_H + +#include "misc_util.h" + +CMPIStatus enum_switches(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const CMPIResult *results, + bool names_only); + +CMPIStatus get_switch_by_ref(const CMPIBroker *broker, + const CMPIObjectPath *reference, + CMPIInstance **_inst); + + +CMPIStatus get_switch_by_name(const CMPIBroker *broker, + const char *name, + const CMPIObjectPath *reference, + CMPIInstance **_inst); + + +#endif + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ -- 1.7.6 From xiawenc at linux.vnet.ibm.com Thu Jan 12 09:46:50 2012 From: xiawenc at linux.vnet.ibm.com (Wayne Xia) Date: Thu, 12 Jan 2012 17:46:50 +0800 Subject: [Libvirt-cim] [V3 PATCH 06/10] CIM model - Makefile change In-Reply-To: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1326361614-18674-7-git-send-email-xiawenc@linux.vnet.ibm.com> Simply change the makefile to introduce the classes. Signed-off-by: Wayne Xia --- Makefile.am | 14 +++++++++++--- src/Makefile.am | 23 ++++++++++++++++++++--- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index 5f004ec..4d14e61 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ # Copyright IBM Corp. 2007 AUTOMAKE_OPTIONS=dist-bzip2 -SUBDIRS = libxkutil src doc base_schema +SUBDIRS = libnetwork libxkutil src doc base_schema MOFS = \ schema/ComputerSystem.mof \ @@ -63,7 +63,11 @@ MOFS = \ schema/EntriesInFilterList.mof \ schema/NestedFilterList.mof \ schema/AppliedFilterList.mof \ - schema/HostedFilterList.mof + schema/HostedFilterList.mof \ + schema/VirtualEthernetSwitchSystem.mof \ + schema/VirtualEthernetSwitchSystemSettingData.mof \ + schema/EthernetPort.mof \ + schema/EthernetPortAllocationSettingData.mof INTEROP_MOFS = \ schema/ComputerSystem.mof \ @@ -150,7 +154,11 @@ REGS = \ schema/EntriesInFilterList.registration \ schema/NestedFilterList.registration \ schema/AppliedFilterList.registration \ - schema/HostedFilterList.registration + schema/HostedFilterList.registration \ + schema/VirtualEthernetSwitchSystem.registration \ + schema/VirtualEthernetSwitchSystemSettingData.registration \ + schema/EthernetPort.registration \ + schema/EthernetPortAllocationSettingData.registration INTEROP_REGS = \ schema/RegisteredProfile.registration \ diff --git a/src/Makefile.am b/src/Makefile.am index e4e8aa1..51aa596 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,11 +25,16 @@ noinst_HEADERS = profiles.h svpc_types.h \ Virt_ConsoleRedirectionServiceCapabilities.h \ Virt_KVMRedirectionSAP.h \ Virt_FilterList.h \ - Virt_FilterEntry.h + Virt_FilterEntry.h \ + Virt_VirtualEthernetSwitchSystem.h \ + Virt_VESSSD.h \ + Virt_EthernetPort.h \ + Virt_EASD.h XKUADD = $(top_builddir)/libxkutil/libxkutil.la +NTWADD = $(top_builddir)/libnetwork/libnetwork.la -CFLAGS += -I$(top_srcdir)/libxkutil $(CFLAGS_STRICT) +CFLAGS += -I$(top_srcdir)/libxkutil -I$(top_srcdir)/libnetwork $(CFLAGS_STRICT) AM_LDFLAGS = $(XKUADD) \ -version-info @VERSION_INFO@ @@ -86,7 +91,11 @@ provider_LTLIBRARIES = libVirt_ComputerSystem.la \ libVirt_EntriesInFilterList.la \ libVirt_NestedFilterList.la \ libVirt_HostedFilterList.la \ - libVirt_AppliedFilterList.la + libVirt_AppliedFilterList.la \ + libVirt_VirtualEthernetSwitchSystem.la \ + libVirt_VESSSD.la \ + libVirt_EthernetPort.la \ + libVirt_EASD.la libVirt_ComputerSystem_la_SOURCES = Virt_ComputerSystem.c libVirt_ComputerSystem_la_DEPENDENCIES = libVirt_VirtualSystemSnapshotService.la @@ -275,3 +284,11 @@ libVirt_HostedFilterList_la_LIBADD = -lVirt_HostSystem -lVirt_FilterList libVirt_AppliedFilterList_la_DEPENDENCIES = libVirt_Device.la libVirt_FilterList.la libVirt_AppliedFilterList_la_SOURCES = Virt_AppliedFilterList.c libVirt_AppliedFilterList_la_LIBADD = -lVirt_Device -lVirt_FilterList + +libVirt_VirtualEthernetSwitchSystem_la_SOURCES = Virt_VirtualEthernetSwitchSystem.c + +libVirt_VESSSD_la_SOURCES = Virt_VESSSD.c + +libVirt_EthernetPort_la_SOURCES = Virt_EthernetPort.c + +libVirt_EASD_la_SOURCES = Virt_EASD.c -- 1.7.6 From xiawenc at linux.vnet.ibm.com Thu Jan 12 09:46:53 2012 From: xiawenc at linux.vnet.ibm.com (Wayne Xia) Date: Thu, 12 Jan 2012 17:46:53 +0800 Subject: [Libvirt-cim] [V3 PATCH 09/10] CIM model - EthernetPort In-Reply-To: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1326361614-18674-10-git-send-email-xiawenc@linux.vnet.ibm.com> EthernetPort is very similar to NetworkPort but was requied by modeling Switch System. This patch consider physical ethernet ports and virtual ports on host side as EthernetPort, it do not touch ports on VM side. Signed-off-by: Wayne Xia --- schema/EthernetPort.mof | 4 + schema/EthernetPort.registration | 3 + src/Virt_EthernetPort.c | 561 ++++++++++++++++++++++++++++++++++++++ src/Virt_EthernetPort.h | 58 ++++ 4 files changed, 626 insertions(+), 0 deletions(-) create mode 100644 schema/EthernetPort.mof create mode 100644 schema/EthernetPort.registration create mode 100644 src/Virt_EthernetPort.c create mode 100644 src/Virt_EthernetPort.h diff --git a/schema/EthernetPort.mof b/schema/EthernetPort.mof new file mode 100644 index 0000000..4a81c91 --- /dev/null +++ b/schema/EthernetPort.mof @@ -0,0 +1,4 @@ +// Copyright IBM Corp. 2011 +class Net_EthernetPort : CIM_EthernetPort +{ +}; diff --git a/schema/EthernetPort.registration b/schema/EthernetPort.registration new file mode 100644 index 0000000..67320d0 --- /dev/null +++ b/schema/EthernetPort.registration @@ -0,0 +1,3 @@ +# Copyright IBM Corp. 2011 +# Classname Namespace ProviderName ProviderModule ProviderTypes +Net_EthernetPort root/virt Virt_EthernetPort Virt_EthernetPort instance diff --git a/src/Virt_EthernetPort.c b/src/Virt_EthernetPort.c new file mode 100644 index 0000000..f237886 --- /dev/null +++ b/src/Virt_EthernetPort.c @@ -0,0 +1,561 @@ +/* + * Copyright IBM Corp. 2007 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "misc_util.h" +#include "cs_util.h" +#include "device_parsing.h" +#include "network_model_helper.h" + +#include "Virt_EthernetPort.h" + +static const CMPIBroker *_BROKER; + +static int set_primary_for_ep(const CMPIBroker *broker, const char* prefix, + EthIface *piface, CMPIInstance *instance) +{ + char *eth_name, *ep_name; + const char *syscls_name = "Virt_VirtualEthernetSwitchSystem"; + int asret; + + if (piface->name == NULL) { + return 0; + } + + eth_name = get_ethport_name_from_iface(piface->name); + asret = asprintf(&ep_name, "%s/%s", prefix, eth_name); + + CMSetProperty(instance, "DeviceID", + (CMPIValue *)ep_name, CMPI_chars); + + CMSetProperty(instance, "InstanceID", + (CMPIValue *)ep_name, CMPI_chars); + + CMSetProperty(instance, "ElementName", + (CMPIValue *)eth_name, CMPI_chars); + SAFE_FREE(ep_name); + SAFE_FREE(eth_name); + + CMSetProperty(instance, "SystemCreationClassName", + (CMPIValue *)syscls_name, CMPI_chars); + + CMSetProperty(instance, "SystemName", + (CMPIValue *)prefix, CMPI_chars); + + return 1; +} + +static int set_secondary_for_ep(const CMPIBroker *broker, EthIface *piface, + CMPIInstance *instance) +{ + int state; + uint16_t cim_type; + CMPIArray *array; + CMPIStatus s; + CMPIString *str; + + if (piface->run_prop.state == ETH_STATE_DOWN) { + state = CIM_STATE_DISABLED; + } else if (piface->run_prop.state == ETH_STATE_UP) { + state = CIM_STATE_ENABLED; + } else { + state = CIM_STATE_UNKNOWN; + } + CMSetProperty(instance, "EnabledState", + (CMPIValue *)&state, CMPI_uint16); + CMSetProperty(instance, "RequestedState", + (CMPIValue *)&state, CMPI_uint16); + + cim_type = CIM_NUM_NET_ETHERNET; + CMSetProperty(instance, "LinkTechnology", + (CMPIValue *)&cim_type, CMPI_uint16); + + if (piface->mac != NULL) { + array = CMNewArray(broker, 1, CMPI_string, &s); + if ((s.rc != CMPI_RC_OK) || (CMIsNullObject(array))) { + CU_DEBUG("failed to create array."); + return 0; + } + str = CMNewString(broker, piface->mac, &s); + if ((s.rc != CMPI_RC_OK) || (CMIsNullObject(str))) { + CU_DEBUG("failed to create array."); + return 0; + } + + CMSetArrayElementAt(array, 0, &str, CMPI_string); + + CMSetProperty(instance, "NetworkAddresses", + (CMPIValue *)&array, CMPI_stringA); + } + + return 1; +} + +static CMPIStatus set_properties(const CMPIBroker *broker, + EthIface *piface, + const char *prefix, + CMPIInstance *instance) +{ + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; + char *errstr; + + if (!set_primary_for_ep(broker, prefix, piface, instance)) { + errstr = "failed to set primary properties for instance."; + CU_DEBUG("%s, iface name %s.", errstr, piface->name); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + if (!set_secondary_for_ep(broker, piface, instance)) { + errstr = "failed to set secondary properties for instance."; + CU_DEBUG("%s, iface name %s.", errstr, piface->name); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + cu_statusf(broker, &s, + CMPI_RC_OK, + ""); + + out: + return s; +} + + +static CMPIStatus instance_from_ep_build(const CMPIBroker *broker, + EthIface *piface, + const char *prefix, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst) +{ + CMPIInstance *inst = NULL; + CMPIStatus s = {CMPI_RC_OK, NULL}; + const char *keys[] = {"InstanceID", NULL}; + + inst = get_typed_instance(broker, + NETWORK_CLASS_PREFIX, + "EthernetPort", + NAMESPACE(reference)); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to init ep instance"); + goto out; + } + + s = CMSetPropertyFilter(inst, properties, keys); + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("Unable to set property filter: %d", s.rc); + } + + s = set_properties(broker, + piface, + prefix, + inst); + + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + return s; +} + + +static CMPIStatus instance_from_ep(const CMPIBroker *broker, + EthIface *piface, + const char *vsname, + const CMPIObjectPath *reference, + const char **properties, + struct inst_list *plist) +{ + + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *br1_name = NULL, *br2_name = NULL; + + get_possible_bridge_name_for_cim_model(piface, &br1_name, &br2_name); + if (br1_name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to find any bridge for the port."); + CU_DEBUG("failed to find any bridge for the port %s.", + piface->name); + goto out; + } + + /* building up the instance */ + if ((vsname == NULL) || (0 == strcmp(vsname, br1_name))) { + inst = NULL; + s = instance_from_ep_build(broker, + piface, + br1_name, + reference, + properties, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(plist, inst); + } + + /* following is to make it comform to CIM profile which require two + ethports connectted to pNIC and vswitch, but we have only one piface + on linux indicating it is connected to pNIC and bridge at sametime */ + if (br2_name == NULL) { + goto out; + } + + if ((vsname == NULL) || (0 == strcmp(vsname, br2_name))) { + inst = NULL; + s = instance_from_ep_build(broker, + piface, + br2_name, + reference, + properties, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(plist, inst); + } + + + out: + SAFE_FREE(br1_name); + SAFE_FREE(br2_name); + return s; +} + +CMPIStatus get_ep_by_name(const CMPIBroker *broker, + const char *prefix, + const char *name, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *eth_name = NULL; + char *dest = NULL; + char *errstr; + int ret; + EthIfacesList ifaces_list; + struct inst_list list; + + eth_ifaceslist_init(&ifaces_list); + inst_list_init(&list); + + eth_name = get_iface_name_from_ethport(name); + if (eth_name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to convert instance name"); + CU_DEBUG("ethport name %s failed to convert.", name); + goto out; + } + + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_cim_ethport_for_name, eth_name); + + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + if (ifaces_list.count != 1) { + errstr = "expected ethport not found."; + CU_DEBUG("%s\n", errstr); + eth_ifaceslist_print(&ifaces_list); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + inst = NULL; + s = instance_from_ep(broker, + ifaces_list.pifaces[0], + prefix, + reference, + properties, + &list); + + if (s.rc != CMPI_RC_OK) { + goto out; + } + + if (list.cur == 0) { + CU_DEBUG("%d instance found, expect is 1.", list.cur); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "no such instance."); + goto out; + } + + if (list.cur > 1) { + CU_DEBUG("%d instance found, expect is 1.", list.cur); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "instance found do not match expectation"); + goto out; + } + + *_inst = list.list[0]; + list.list[0] = NULL; + + out: + eth_ifaceslist_uninit(&ifaces_list); + inst_list_free(&list); + SAFE_FREE(eth_name); + SAFE_FREE(dest); + return s; +} + +CMPIStatus get_ep_by_id(const CMPIBroker *broker, + const char *id, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + char *prefix = NULL; + char *suffix = NULL; + if (id == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_INVALID_PARAMETER, + "ID is NULL'", id); + } + if (!parse_fq_devid(id, &prefix, &suffix) || (prefix == NULL) || + (suffix == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_INVALID_PARAMETER, + "Invalid InstanceID `%s'", id); + goto out; + } + s = get_ep_by_name(broker, prefix, suffix, reference, + properties, _inst); + + out: + SAFE_FREE(prefix); + SAFE_FREE(suffix); + return s; +} + +CMPIStatus get_ep_by_ref(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *name = NULL; + char *prefix = NULL; + const char *id; + + if (cu_get_str_path(reference, "DeviceID", &id) != CMPI_RC_OK) { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_FOUND, + "No such instance (InstanceID)"); + goto out; + } + if ((!parse_fq_devid(id, &prefix, &name)) || + (name == NULL) || (prefix == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_FOUND, + "Failed to translate (InstanceID)"); + goto out; + } + + s = get_ep_by_name(broker, prefix, name, reference, + properties, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + s = cu_validate_ref(broker, reference, inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + free(name); + free(prefix); + + return s; +} + + +CMPIStatus enum_eps(const CMPIBroker *broker, + const char *ref_vsname, + const CMPIObjectPath *reference, + const char **properties, + struct inst_list *plist) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + EthIfacesList ifaces_list; + int ret, i; + char *errstr; + + eth_ifaceslist_init(&ifaces_list); + + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_cim_ethport, NULL); + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + CU_DEBUG("enum ep, found following devices.") + eth_ifaceslist_print(&ifaces_list); + + i = 0; + while (i < ifaces_list.count) { + s = instance_from_ep(broker, + ifaces_list.pifaces[i], + ref_vsname, + reference, + properties, + plist); + i++; + /* this should never fail */ + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("unexpected fail."); + break; + } + } + + + out: + eth_ifaceslist_uninit(&ifaces_list); + + return s; +} + +static CMPIStatus return_enum_eps(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const CMPIResult *results, + const char **properties, + const bool names_only) +{ + struct inst_list list; + CMPIStatus s = {CMPI_RC_OK, NULL}; + inst_list_init(&list); + s = enum_eps(broker, NULL, reference, properties, &list); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + if (names_only) { + cu_return_instance_names(results, &list); + } else { + cu_return_instances(results, &list); + } + + out: + inst_list_free(&list); + return s; +} + +static CMPIStatus EnumInstanceNames(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference) +{ + return return_enum_eps(_BROKER, reference, results, NULL, true); +} + +static CMPIStatus EnumInstances(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const char **properties) +{ + + return return_enum_eps(_BROKER, reference, results, properties, false); +} + +static CMPIStatus GetInstance(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *ref, + const char **properties) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + + s = get_ep_by_ref(_BROKER, ref, properties, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + CMReturnInstance(results, inst); + + out: + return s; +} + +DEFAULT_CI(); +DEFAULT_MI(); +DEFAULT_DI(); +DEFAULT_INST_CLEANUP(); +DEFAULT_EQ(); + +STD_InstanceMIStub(, + Virt_EthernetPort, + _BROKER, + libvirt_cim_init()); + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/Virt_EthernetPort.h b/src/Virt_EthernetPort.h new file mode 100644 index 0000000..f474af2 --- /dev/null +++ b/src/Virt_EthernetPort.h @@ -0,0 +1,58 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wencao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __VIRT_ETHERNETPORT_H +#define __VIRT_ETHERNETPORT_H + +CMPIStatus enum_eps(const CMPIBroker *broker, + const char *ref_vsname, + const CMPIObjectPath *reference, + const char **properties, + struct inst_list *plist); + +CMPIStatus get_ep_by_name(const CMPIBroker *broker, + const char *prefix, + const char *name, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst); + +CMPIStatus get_ep_by_id(const CMPIBroker *broker, + const char *id, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst); + +CMPIStatus get_ep_by_ref(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst); + +#endif + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ -- 1.7.6 From xiawenc at linux.vnet.ibm.com Thu Jan 12 09:46:54 2012 From: xiawenc at linux.vnet.ibm.com (Wayne Xia) Date: Thu, 12 Jan 2012 17:46:54 +0800 Subject: [Libvirt-cim] [V3 PATCH 10/10] CIM model - EASD In-Reply-To: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1326361614-18674-11-git-send-email-xiawenc@linux.vnet.ibm.com> SettingData of EthernetPort. According to DSP1097, it have two types: EA and EC. EA says what the port is, EC says the connection it have. Additional property VLANType was added to distiguish if it is 802.1.q vlan or other. Signed-off-by: Wayne Xia --- schema/EthernetPortAllocationSettingData.mof | 21 + .../EthernetPortAllocationSettingData.registration | 3 + src/Virt_EASD.c | 729 ++++++++++++++++++++ src/Virt_EASD.h | 59 ++ 4 files changed, 812 insertions(+), 0 deletions(-) create mode 100644 schema/EthernetPortAllocationSettingData.mof create mode 100644 schema/EthernetPortAllocationSettingData.registration create mode 100644 src/Virt_EASD.c create mode 100644 src/Virt_EASD.h diff --git a/schema/EthernetPortAllocationSettingData.mof b/schema/EthernetPortAllocationSettingData.mof new file mode 100644 index 0000000..8a1b38b --- /dev/null +++ b/schema/EthernetPortAllocationSettingData.mof @@ -0,0 +1,21 @@ +// Copyright IBM Corp. 2011 + +[Description ("Virtutal EthernetPort Setting Data"), + Provider("cmpi::Virt_EASD") +] + +class Net_EthernetPortAllocationSettingData : CIM_EthernetPortAllocationSettingData +{ + uint16 PortVID; + uint16 DesiredEndPointMode; + + [Description("VLAN type of the port, " + "Now only support IEEE 802.1.q."), + ValueMap { "0", "1", "2", "3" }, + Values { "Not VLAN", "IEEE 802.1.q", "IEEE 802.1.qbg", "IEEE 802.1.qbh" }] + uint16 VLANType; + + uint16 ReorderHdr; + string VLANQosIngress; + string VLANQosEgress; +}; diff --git a/schema/EthernetPortAllocationSettingData.registration b/schema/EthernetPortAllocationSettingData.registration new file mode 100644 index 0000000..bedd029 --- /dev/null +++ b/schema/EthernetPortAllocationSettingData.registration @@ -0,0 +1,3 @@ +# Copyright IBM Corp. 2011 +# Classname Namespace ProviderName ProviderModule ProviderTypes +Net_EthernetPortAllocationSettingData root/virt Virt_EASD Virt_EASD instance diff --git a/src/Virt_EASD.c b/src/Virt_EASD.c new file mode 100644 index 0000000..e24dfd8 --- /dev/null +++ b/src/Virt_EASD.c @@ -0,0 +1,729 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "misc_util.h" +#include "cs_util.h" +#include "device_parsing.h" +#include "network_model_helper.h" + +#include "Virt_EASD.h" + +static const CMPIBroker *_BROKER; + +static int set_primary_for_easd(const CMPIBroker *broker, const char* prefix, + EthIface *piface, int type, CMPIInstance *instance) +{ + char *eth_name, *easd_name; + int asret; + uint16_t res_type = CIM_NUM_SWITCHPORT; + uint16_t vlan_mode; + + if (piface->name == NULL) { + return 0; + } + + eth_name = get_ethportsd_name_from_iface(piface->name, type); + asret = asprintf(&easd_name, "%s/%s", prefix, eth_name); + + CMSetProperty(instance, "InstanceID", + (CMPIValue *)easd_name, CMPI_chars); + CMSetProperty(instance, "ElementName", + (CMPIValue *)eth_name, CMPI_chars); + SAFE_FREE(easd_name); + SAFE_FREE(eth_name); + + CMSetProperty(instance, "ResourceType", + (CMPIValue *)&res_type, CMPI_uint16); + + if ((piface->eth_type & ETH_TYPE_ETHER_ANY) && + (piface->eth_type & ETH_TYPE_ETHER_SUB_PHYSICAL)) { + vlan_mode = CIM_NUM_VLAN_MODE_TRUNK; + CMSetProperty(instance, "DesiredEndPointMode", + (CMPIValue *)&vlan_mode, CMPI_uint16); + } + + + if (piface->mac != NULL) { + CMSetProperty(instance, "Address", + (CMPIValue *)piface->mac, CMPI_chars); + } + + return 1; +} + +static int set_secondary_for_easd(const CMPIBroker *broker, EthIface *piface, + CMPIInstance *instance) +{ + VLAN_Prop *pvlan; + VLAN_Prop_8021q *pvlan8021q; + uint16_t vid, hdr; + CMPIArray *conn_array; + CMPIString *cm_str; + char *str = NULL, *egress = NULL, *ingress = NULL; + CMPIStatus s; + int ret; + uint16_t vlantype = 0; + uint16_t visibility = CIM_NUM_CONSUMERVISIBILITY_VIRTUALIZED; + + if ((piface->eth_type & ETH_TYPE_ETHER_ANY) && + (piface->eth_type & ETH_TYPE_ETHER_SUB_PHYSICAL)) { + visibility = CIM_NUM_CONSUMERVISIBILITY_PASSEDTHROUGH; + } + CMSetProperty(instance, "ConsumerVisibility", + (CMPIValue *)&visibility, CMPI_uint16); + + if (!(piface->eth_type & ETH_TYPE_ETHER_SUB_VLAN) || + (piface->pvlan_prop == NULL)) { + goto out; + } + pvlan = piface->pvlan_prop; + + if (pvlan->vlan_type == VLAN_TYPE_802_1_Q) { + pvlan8021q = &(pvlan->props.prop_8021q); + vid = pvlan8021q->vlan_id; + CMSetProperty(instance, "PortVID", + (CMPIValue *)&vid, CMPI_uint16); + + str = vlanid_to_connection_name(vid); + conn_array = CMNewArray(broker, 1, CMPI_string, &s); + if ((s.rc != CMPI_RC_OK) || (str == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Error creating Connection " + "list and its string"); + CU_DEBUG("CMNewArray or string creation failed"); + goto out; + } + cm_str = CMNewString(broker, str, &s); + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("Error creating CMPIString"); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Error creating CMPIString for " + "BootDevices item"); + + goto out; + } + CMSetArrayElementAt(conn_array, 0, (CMPIValue *)&cm_str, + CMPI_string); + CMSetProperty(instance, "Connection", + (CMPIValue *)&conn_array, CMPI_stringA); + hdr = pvlan8021q->reorder_hdr; + CMSetProperty(instance, "ReorderHdr", + (CMPIValue *)&hdr, CMPI_uint16); + + if ((pvlan8021q->ingress.count > 0) && + (pvlan8021q->ingress.count <= 8)) { + ret = vlan_8021q_qos_num_to_str(&ingress, + &(pvlan8021q->ingress)); + if (ret == 1) { + CMSetProperty(instance, "VLANQosIngress", + (CMPIValue *)ingress, CMPI_chars); + } else { + CU_DEBUG("failed to generate vlan qos " + "string."); + } + } + if ((pvlan8021q->egress.count > 0) && + (pvlan8021q->egress.count <= 8)) { + ret = vlan_8021q_qos_num_to_str(&egress, + &(pvlan8021q->egress)); + if (ret == 1) { + CMSetProperty(instance, "VLANQosEgress", + (CMPIValue *)egress, CMPI_chars); + } else { + CU_DEBUG("failed to generate vlan qos " + "string."); + } + } + vlantype = 1; + } + CMSetProperty(instance, "VLANType", + (CMPIValue *)&vlantype, CMPI_uint16); + +out: + SAFE_FREE(str); + SAFE_FREE(egress); + SAFE_FREE(ingress); + return 1; +} + +static CMPIStatus add_conn_properties(const CMPIBroker *broker, + EthIface *piface, + const char *prefix, + const char *dest, + CMPIInstance *instance) +{ + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; + char *eth_name, *easd_name; + int asret; + CMPIArray *array; + CMPIString *tmp; + + if (piface->name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "device name not set"); + goto out; + } + if (dest == NULL) { + CU_DEBUG("warn: connection dest is NULL."); + } + + eth_name = get_ethportsd_name_from_iface(piface->name, EASD_TYPE_EA); + asret = asprintf(&easd_name, "%s:%s", prefix, eth_name); + CMSetProperty(instance, "Parent", + (CMPIValue *)easd_name, CMPI_chars); + SAFE_FREE(easd_name); + SAFE_FREE(eth_name); + + array = CMNewArray(broker, 1, CMPI_string, &s); + tmp = CMNewString(broker, dest, NULL); + CMSetArrayElementAt(array, 0, &(tmp), CMPI_string); + CMSetProperty(instance, "HostResource", + (CMPIValue *)&array, CMPI_stringA); + + + out: + return s; +} + +static CMPIStatus set_properties(const CMPIBroker *broker, + EthIface *piface, + const char *prefix, + const char *dest, + int type, + CMPIInstance *instance) +{ + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; + char *errstr; + + if (!set_primary_for_easd(broker, prefix, piface, type, instance)) { + errstr = "failed to set primary properties for instance."; + CU_DEBUG("%s, iface name %s.", errstr, piface->name); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + if (type == EASD_TYPE_EA) { + if (!set_secondary_for_easd(broker, piface, instance)) { + errstr = "failed to set secondary properties" + " for instance."; + CU_DEBUG("%s, iface name %s.", errstr, piface->name); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + } else { + s = add_conn_properties(broker, + piface, + prefix, + dest, + instance); + if (s.rc != CMPI_RC_OK) { + goto out; + } + } + + cu_statusf(broker, &s, + CMPI_RC_OK, + ""); + + out: + return s; +} + +static CMPIStatus instance_from_easd_build(const CMPIBroker *broker, + EthIface *piface, + const char *prefix, + const char *dest, + int type, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst) +{ + CMPIInstance *inst = NULL; + CMPIStatus s = {CMPI_RC_OK, NULL}; + const char *keys[] = {"InstanceID", NULL}; + + inst = get_typed_instance(broker, + NETWORK_CLASS_PREFIX, + "EthernetPortAllocationSettingData", + NAMESPACE(reference)); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to init SwitchSystem instance"); + goto out; + } + + + s = CMSetPropertyFilter(inst, properties, keys); + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("Unable to set property filter: %d", s.rc); + } + + s = set_properties(broker, + piface, + prefix, + dest, + type, + inst); + + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + return s; +} + +/* vsname and req_type are filter conditions */ +static CMPIStatus instance_from_easd(const CMPIBroker *broker, + EthIface *piface, + const char *vsname, + int req_type, + const CMPIObjectPath *reference, + const char **properties, + struct inst_list *plist) +{ + + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *br1_name = NULL, *br2_name = NULL; + + CU_DEBUG("enter instance_for_easd with vsname %s, type %d.", + vsname, req_type); + get_possible_bridge_name_for_cim_model(piface, &br1_name, &br2_name); + if (br1_name == NULL) { + CU_DEBUG("failed to find any bridge for the port %s.", + piface->name); + } + + /* building the EA instance */ + if (!(req_type&EASD_TYPE_EA)) { + goto ea_build_end; + } + if ((vsname == NULL) || (br1_name == NULL) || + (0 == strcmp(vsname, br1_name))) { + inst = NULL; + s = instance_from_easd_build(broker, + piface, + br1_name, + NULL, + EASD_TYPE_EA, + reference, + properties, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(plist, inst); + } + + /* following is to make it comform to CIM profile which require two + ethports connectted to pNIC and vswitch, but we have only one piface + on linux indicating it is connected to pNIC and bridge at sametime */ + if (br2_name == NULL) { + goto out; + } + + if ((vsname == NULL) || (0 == strcmp(vsname, br2_name))) { + inst = NULL; + s = instance_from_easd_build(broker, + piface, + br2_name, + NULL, + EASD_TYPE_EA, + reference, + properties, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(plist, inst); + } + ea_build_end: + + /* building the EC instance */ + if (!(req_type&EASD_TYPE_EC)) { + goto ec_build_end; + } + if ((br1_name == NULL) || (br2_name == NULL)) { + goto ec_build_end; + } + /* connection exist, so a EC_easd should be added for each bridge */ + if ((vsname == NULL) || (0 == strcmp(vsname, br1_name))) { + inst = NULL; + s = instance_from_easd_build(broker, + piface, + br1_name, + br2_name, + EASD_TYPE_EC, + reference, + properties, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(plist, inst); + } + if ((vsname == NULL) || (0 == strcmp(vsname, br2_name))) { + inst = NULL; + s = instance_from_easd_build(broker, + piface, + br2_name, + br1_name, + EASD_TYPE_EC, + reference, + properties, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(plist, inst); + } + ec_build_end: + + out: + SAFE_FREE(br1_name); + SAFE_FREE(br2_name); + return s; +} + +CMPIStatus get_easd_by_name(const CMPIBroker *broker, + const char *prefix, + const char *name, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *eth_name = NULL; + char *dest = NULL; + char *errstr; + int ret; + int type; + EthIfacesList ifaces_list; + struct inst_list list; + + CU_DEBUG("####prefix %s", prefix); + eth_ifaceslist_init(&ifaces_list); + inst_list_init(&list); + + eth_name = get_iface_name_from_ethportsd(name, &type); + if (eth_name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to convert instance name"); + CU_DEBUG("ethport name %s failed to convert.", name); + goto out; + } + + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_cim_ethport_for_name, eth_name); + + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + if (ifaces_list.count != 1) { + errstr = "expected ethport not found."; + CU_DEBUG("%d ethportd found.", ifaces_list.count); + eth_ifaceslist_print(&ifaces_list); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + inst = NULL; + s = instance_from_easd(broker, + ifaces_list.pifaces[0], + prefix, + type, + reference, + properties, + &list); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + if (list.cur == 0) { + CU_DEBUG("%d instance found, expect is 1.", list.cur); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "no such instance."); + goto out; + } + + if (list.cur > 1) { + CU_DEBUG("%d instance found, expect is 1.", list.cur); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "instance found do not match expectation"); + goto out; + } + + *_inst = list.list[0]; + list.list[0] = NULL; + + out: + eth_ifaceslist_uninit(&ifaces_list); + inst_list_free(&list); + SAFE_FREE(eth_name); + SAFE_FREE(dest); + return s; +} + +CMPIStatus get_easd_by_id(const CMPIBroker *broker, + const char *id, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + char *prefix = NULL; + char *suffix = NULL; + if (id == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_INVALID_PARAMETER, + "ID is NULL'", id); + } + if (!parse_fq_devid(id, &prefix, &suffix) || (prefix == NULL) || + (suffix == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_INVALID_PARAMETER, + "Invalid InstanceID `%s'", id); + goto out; + } + s = get_easd_by_name(broker, prefix, suffix, reference, + properties, _inst); + + out: + SAFE_FREE(prefix); + SAFE_FREE(suffix); + return s; +} + +CMPIStatus get_easd_by_ref(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *name = NULL; + char *prefix = NULL; + const char *id; + + if (cu_get_str_path(reference, "InstanceID", &id) != CMPI_RC_OK) { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_FOUND, + "No such instance (InstanceID)"); + goto out; + } + if ((!parse_fq_devid(id, &prefix, &name)) || + (name == NULL) || (prefix == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_FOUND, + "Failed to translate (InstanceID)"); + goto out; + } + + s = get_easd_by_name(broker, prefix, name, reference, + properties, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + s = cu_validate_ref(broker, reference, inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + free(name); + free(prefix); + + return s; +} + + +CMPIStatus enum_easds(const CMPIBroker *broker, + const char *ref_vsname, + const CMPIObjectPath *reference, + const char **properties, + struct inst_list *plist) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + EthIfacesList ifaces_list; + int ret, i; + char *errstr; + + eth_ifaceslist_init(&ifaces_list); + + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_cim_ethport, NULL); + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + CU_DEBUG("enum easd, found following devices.") + eth_ifaceslist_print(&ifaces_list); + + i = 0; + while (i < ifaces_list.count) { + s = instance_from_easd(broker, + ifaces_list.pifaces[i], + ref_vsname, + EASD_TYPE_EA|EASD_TYPE_EC, + reference, + properties, + plist); + i++; + /* this should never fail */ + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("unexpected fail."); + break; + } + } + + + out: + eth_ifaceslist_uninit(&ifaces_list); + + return s; +} + +static CMPIStatus return_enum_easds(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const CMPIResult *results, + const char **properties, + const bool names_only) +{ + struct inst_list list; + CMPIStatus s = {CMPI_RC_OK, NULL}; + inst_list_init(&list); + s = enum_easds(broker, NULL, reference, properties, &list); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + if (names_only) { + cu_return_instance_names(results, &list); + } else { + cu_return_instances(results, &list); + } + + out: + inst_list_free(&list); + return s; +} + +static CMPIStatus EnumInstanceNames(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference) +{ + return return_enum_easds(_BROKER, reference, results, + NULL, true); +} + +static CMPIStatus EnumInstances(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const char **properties) +{ + + return return_enum_easds(_BROKER, reference, results, + properties, false); +} + +static CMPIStatus GetInstance(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *ref, + const char **properties) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + + s = get_easd_by_ref(_BROKER, ref, properties, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + CMReturnInstance(results, inst); + + out: + return s; +} + +DEFAULT_CI(); +DEFAULT_MI(); +DEFAULT_DI(); +DEFAULT_INST_CLEANUP(); +DEFAULT_EQ(); + +STD_InstanceMIStub(, + Virt_EASD, + _BROKER, + libvirt_cim_init()); + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/Virt_EASD.h b/src/Virt_EASD.h new file mode 100644 index 0000000..f9d13ec --- /dev/null +++ b/src/Virt_EASD.h @@ -0,0 +1,59 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __VIRT_EASD_H +#define __VIRT_EASD_H + +CMPIStatus enum_easds(const CMPIBroker *broker, + const char *ref_vsname, + const CMPIObjectPath *reference, + const char **properties, + struct inst_list *plist); + +CMPIStatus get_easd_by_name(const CMPIBroker *broker, + const char *prefix, + const char *name, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst); + +CMPIStatus get_easd_by_id(const CMPIBroker *broker, + const char *id, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst); + +CMPIStatus get_easd_by_ref(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst); + + +#endif + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ -- 1.7.6 From xiawenc at linux.vnet.ibm.com Thu Jan 12 09:46:46 2012 From: xiawenc at linux.vnet.ibm.com (Wayne Xia) Date: Thu, 12 Jan 2012 17:46:46 +0800 Subject: [Libvirt-cim] [V3 PATCH 02/10] building system modification for libnl3 and libbridge In-Reply-To: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1326361614-18674-3-git-send-email-xiawenc@linux.vnet.ibm.com> As patch 1/10 says, this is the libtool making system for libnl3 and libbridge. Now it only compile core and route components of libnl3, but other source code were also put in the ./libnl3 in case using in the future. Note: Because in root directory the autoconfigure have modification of glabal variable CFLAGS and LDFLAGS containing information it have to drop, these Makefile now override these values, so ./configure CFLAGS would not take effect in these directories now. New Macro were introduced in configure.ac to set the compile and linking option for ./libnetwork directory. -fvisibility=hidden and -D DLL_BUILD were used to limit symbols exported. Signed-off-by: Wayne Xia --- configure.ac | 19 +++++- libnetwork/libbridge/Makefile.am | 20 ++++++ libnetwork/libnl3/Makefile.am | 8 ++ libnetwork/libnl3/include/Makefile.am | 122 +++++++++++++++++++++++++++++++++ libnetwork/libnl3/lib/Makefile.am | 99 ++++++++++++++++++++++++++ 5 files changed, 267 insertions(+), 1 deletions(-) create mode 100644 libnetwork/libbridge/Makefile.am create mode 100644 libnetwork/libnl3/Makefile.am create mode 100644 libnetwork/libnl3/include/Makefile.am create mode 100644 libnetwork/libnl3/lib/Makefile.am diff --git a/configure.ac b/configure.ac index 0250c73..bae3de0 100644 --- a/configure.ac +++ b/configure.ac @@ -14,7 +14,7 @@ AC_CONFIG_SRCDIR([src/Virt_ComputerSystem.c]) AC_CONFIG_HEADER([config.h]) # Use silent rules if possible -AM_INIT_AUTOMAKE +AM_INIT_AUTOMAKE([-Wall foreign subdir-objects]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) m4_define([lt_cur], m4_eval(libvirtcim_maj + libvirtcim_min)) @@ -50,6 +50,18 @@ CC_WARNINGS="\ CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE -D_LARGEFILE64_SOURCE" +# following are for libnetwork +LIBNETWORK_CFLAGS="-fvisibility=hidden" +LIBNETWORK_DEFINES="-D DLL_BUILD" +AC_SUBST(LIBNETWORK_CFLAGS) +AC_SUBST(LIBNETWORK_DEFINES) + +AM_CONDITIONAL([LIBNL3_ENABLE_CLI], [test "$enable_cli" = "yes"]) + +# LEX and YACC is neccessary for libnl-3 +AM_PROG_LEX +AC_PROG_YACC + # Configure command line options AC_ARG_VAR([CIMSERVER],[the target CIM server (pegasus|sfcb|openwbem|sniacimom). ]) @@ -142,6 +154,11 @@ AC_CONFIG_FILES([ base_schema/Makefile libxkutil/Makefile libxkutil/tests/Makefile + libnetwork/Makefile + libnetwork/libbridge/Makefile + libnetwork/libnl3/Makefile + libnetwork/libnl3/lib/Makefile + libnetwork/libnl3/include/Makefile src/Makefile src/tests/Makefile doc/Makefile diff --git a/libnetwork/libbridge/Makefile.am b/libnetwork/libbridge/Makefile.am new file mode 100644 index 0000000..93646fb --- /dev/null +++ b/libnetwork/libbridge/Makefile.am @@ -0,0 +1,20 @@ +# Copyright IBM Corp. 2011 +# Auther: +# Wenchao Xia, +# +# These code is a taken from bridge-utils-1.5 + +CFLAGS = $(LIBNETWORK_CFLAGS) \ + $(LIBNETWORK_DEFINES) +CPPFLAGS = +LDFLAGS = $(LIBNETWORK_DEFINES) + +AM_CFLAGS = $(CFLAGS_STRICT) \ + -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" + +noinst_HEADERS = libbridge_private.h libbridge.h + +noinst_LTLIBRARIES = libbridge.la + +libbridge_la_SOURCES = libbridge_devif.c libbridge_if.c libbridge_init.c \ + libbridge_misc.c diff --git a/libnetwork/libnl3/Makefile.am b/libnetwork/libnl3/Makefile.am new file mode 100644 index 0000000..3fc7f0f --- /dev/null +++ b/libnetwork/libnl3/Makefile.am @@ -0,0 +1,8 @@ +# Copyright IBM Corp. 2011 +# Auther: +# Wenchao Xia, +# +# This is the root directory just as original +# libnl3 project. + +SUBDIRS = lib include diff --git a/libnetwork/libnl3/include/Makefile.am b/libnetwork/libnl3/include/Makefile.am new file mode 100644 index 0000000..65d7924 --- /dev/null +++ b/libnetwork/libnl3/include/Makefile.am @@ -0,0 +1,122 @@ +# Copyright IBM Corp. 2011 +# Auther: +# Wenchao Xia, +# +# These code is a taken from libnl3-3.2.3, +# it is modified to generate static library. + +noinst_HEADERS = \ + netlink/fib_lookup/lookup.h \ + netlink/fib_lookup/request.h \ + netlink/genl/ctrl.h \ + netlink/genl/family.h \ + netlink/genl/genl.h \ + netlink/genl/mngt.h \ + netlink/netfilter/ct.h \ + netlink/netfilter/log.h \ + netlink/netfilter/log_msg.h \ + netlink/netfilter/netfilter.h \ + netlink/netfilter/nfnl.h \ + netlink/netfilter/queue.h \ + netlink/netfilter/queue_msg.h \ + netlink/addr.h \ + netlink/attr.h \ + netlink/cache-api.h \ + netlink/cache.h \ + netlink/data.h \ + netlink/errno.h \ + netlink/handlers.h \ + netlink/list.h \ + netlink/msg.h \ + netlink/netlink-compat.h \ + netlink/netlink-kernel.h \ + netlink/netlink.h \ + netlink/object-api.h \ + netlink/object.h \ + netlink/route/cls/ematch/cmp.h \ + netlink/route/cls/ematch/meta.h \ + netlink/route/cls/ematch/nbyte.h \ + netlink/route/cls/ematch/text.h \ + netlink/route/cls/basic.h \ + netlink/route/cls/cgroup.h \ + netlink/route/cls/ematch.h \ + netlink/route/cls/fw.h \ + netlink/route/cls/police.h \ + netlink/route/cls/u32.h \ + netlink/route/link/api.h \ + netlink/route/link/bonding.h \ + netlink/route/link/info-api.h \ + netlink/route/link/inet.h \ + netlink/route/link/vlan.h \ + netlink/route/qdisc/cbq.h \ + netlink/route/qdisc/dsmark.h \ + netlink/route/qdisc/fifo.h \ + netlink/route/qdisc/htb.h \ + netlink/route/qdisc/netem.h \ + netlink/route/qdisc/prio.h \ + netlink/route/qdisc/red.h \ + netlink/route/qdisc/sfq.h \ + netlink/route/qdisc/tbf.h \ + netlink/route/addr.h \ + netlink/route/class.h \ + netlink/route/classifier.h \ + netlink/route/link.h \ + netlink/route/neighbour.h \ + netlink/route/neightbl.h \ + netlink/route/nexthop.h \ + netlink/route/pktloc.h \ + netlink/route/qdisc.h \ + netlink/route/route.h \ + netlink/route/rtnl.h \ + netlink/route/rule.h \ + netlink/route/tc.h \ + netlink/route/tc-api.h \ + netlink/socket.h \ + netlink/types.h \ + netlink/utils.h \ + netlink/version.h + +if LIBNL3_ENABLE_CLI +noinst_HEADERS += \ + netlink/cli/addr.h \ + netlink/cli/class.h \ + netlink/cli/cls.h \ + netlink/cli/ct.h \ + netlink/cli/link.h \ + netlink/cli/neigh.h \ + netlink/cli/qdisc.h \ + netlink/cli/route.h \ + netlink/cli/rule.h \ + netlink/cli/tc.h \ + netlink/cli/utils.h +endif + +noinst_HEADERS += \ + linux/fib_rules.h \ + linux/genetlink.h \ + linux/gen_stats.h \ + linux/if_addr.h \ + linux/if_arp.h \ + linux/if_ether.h \ + linux/if.h \ + linux/if_link.h \ + linux/if_vlan.h \ + linux/inetdevice.h \ + linux/ip_mp_alg.h \ + linux/ipv6.h \ + linux/neighbour.h \ + linux/netfilter.h \ + linux/netfilter/nfnetlink_conntrack.h \ + linux/netfilter/nfnetlink.h \ + linux/netfilter/nfnetlink_log.h \ + linux/netfilter/nfnetlink_queue.h \ + linux/netlink.h \ + linux/pkt_cls.h \ + linux/pkt_sched.h \ + linux/rtnetlink.h \ + linux/snmp.h \ + linux/tc_ematch/tc_em_meta.h \ + netlink-generic.h \ + netlink-local.h \ + netlink-tc.h \ + netlink-types.h diff --git a/libnetwork/libnl3/lib/Makefile.am b/libnetwork/libnl3/lib/Makefile.am new file mode 100644 index 0000000..945dca8 --- /dev/null +++ b/libnetwork/libnl3/lib/Makefile.am @@ -0,0 +1,99 @@ +# Copyright IBM Corp. 2011 +# Auther: +# Wenchao Xia, +# +# These code is a taken from libnl3-3.2.3, +# it is modified to generate static library. + +CFLAGS = $(LIBNETWORK_CFLAGS) \ + $(LIBNETWORK_DEFINES) +CPPFLAGS = +LDFLAGS = $(LIBNETWORK_DEFINES) + +AM_CFLAGS = $(CFLAGS_STRICT) \ + -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" + +AM_CPPFLAGS = \ + -Wall \ + -I$(top_srcdir)/libnetwork/libnl3/include \ + -I$(top_srcdir)/libnetwork/libnl3/include/netlink/route \ + -I$(top_srcdir)/libnetwork/libnl3/include/netlink/route/cls \ + -D_GNU_SOURCE \ + -DSYSCONFDIR=\"$(sysconfdir)/libnl\" + +#the code is from libnl-3.2.3 +AM_LDFLAGS = \ + -version-info 3:2:3 + +noinst_LTLIBRARIES = \ + libnl-3-4cim.la libnl-route-3-4cim.la + +libnl_3_4cim_la_SOURCES = \ + addr.c attr.c cache.c cache_mngr.c cache_mngt.c data.c \ + error.c handlers.c msg.c nl.c object.c socket.c utils.c + +CLEANFILES = \ + route/pktloc_grammar.c route/pktloc_grammar.h \ + route/pktloc_syntax.c route/pktloc_syntax.h \ + route/cls/ematch_grammar.c route/cls/ematch_grammar.h \ + route/cls/ematch_syntax.c route/cls/ematch_syntax.h + +# Hack to avoid using ylwrap. It does not function correctly in combination +# with --header-file= +route/pktloc_grammar.c: route/pktloc_grammar.l + $(AM_V_GEN) $(LEX) --header-file=route/pktloc_grammar.h $(LFLAGS) -o $@ $^ + +route/pktloc_syntax.c: route/pktloc_syntax.y + $(AM_V_GEN) $(YACC) -d $(YFLAGS) -o $@ $^ + +route/cls/ematch_grammar.c: route/cls/ematch_grammar.l + $(AM_V_GEN) $(LEX) --header-file=route/cls/ematch_grammar.h $(LFLAGS) -o $@ $^ + +route/cls/ematch_syntax.c: route/cls/ematch_syntax.y + $(AM_V_GEN) $(YACC) -d $(YFLAGS) -o $@ $^ + +libnl_route_3_4cim_la_LIBADD = libnl-3-4cim.la +libnl_route_3_4cim_la_SOURCES = \ + route/addr.c route/class.c route/cls.c route/link.c \ + route/neigh.c route/neightbl.c route/nexthop.c route/qdisc.c \ + route/route.c route/route_obj.c route/route_utils.c route/rtnl.c \ + route/rule.c route/tc.c route/classid.c \ + \ + route/cls/fw.c route/cls/police.c route/cls/u32.c route/cls/basic.c \ + route/cls/cgroup.c \ + \ + route/cls/ematch.c \ + route/cls/ematch/container.c route/cls/ematch/cmp.c \ + route/cls/ematch/nbyte.c route/cls/ematch/text.c \ + route/cls/ematch/meta.c \ + \ + route/link/api.c route/link/vlan.c route/link/dummy.c \ + route/link/bridge.c route/link/inet6.c route/link/inet.c \ + route/link/bonding.c \ + \ + route/qdisc/blackhole.c route/qdisc/cbq.c route/qdisc/dsmark.c \ + route/qdisc/fifo.c route/qdisc/htb.c route/qdisc/netem.c \ + route/qdisc/prio.c route/qdisc/red.c route/qdisc/sfq.c \ + route/qdisc/tbf.c \ + \ + fib_lookup/lookup.c fib_lookup/request.c \ + \ + route/pktloc.c + +nodist_libnl_route_3_4cim_la_SOURCES = \ + route/pktloc_syntax.c route/pktloc_syntax.h \ + route/pktloc_grammar.c route/pktloc_grammar.h \ + route/cls/ematch_syntax.c route/cls/ematch_syntax.h \ + route/cls/ematch_grammar.c route/cls/ematch_grammar.h + +BUILT_SOURCES = \ + route/cls/ematch_grammar.c \ + route/cls/ematch_syntax.c \ + route/pktloc_grammar.c \ + route/pktloc_syntax.c + +EXTRA_DIST = \ + route/pktloc_grammar.l \ + route/pktloc_syntax.y \ + route/cls/ematch_grammar.l \ + route/cls/ematch_syntax.y -- 1.7.6 From xiawenc at linux.vnet.ibm.com Thu Jan 12 09:46:44 2012 From: xiawenc at linux.vnet.ibm.com (Wayne Xia) Date: Thu, 12 Jan 2012 17:46:44 +0800 Subject: [Libvirt-cim] [PATCH v3 00/10] VLAN extension - ReadOnly functions Message-ID: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> These patches would try introduce 4 class with readonly functionality. It used libnl-3 and libbridge as static libarary as an implemention. Program libnetwork_test would be generated under ./libnetwork/.libs/ . Testing: wbemcli -nl ein http://[]:[]@localhost:5988/root/virt:Net_VirtualEthernetSwitchSystem wbemcli -nl ein http://[]:[]@localhost:5988/root/virt:Net_VirtualEthernetSwitchSystemSettingData wbemcli -nl ein http://[]:[]@localhost:5988/root/virt:Net_EthernetPort wbemcli -nl ein http://[]:[]@localhost:5988/root/virt:Net_EthernetPortAllocationSettingData try with command vconfig and brctl modifying the system. Note: These patch only applys on libvirt-cim-0.5.15, Will try move it to 0.6.0 with libvirt 0.9.4 on RH6 on v4 patch. repository: git://gitorious.org/~xiaxia347/libvirt-cim/xiaxia347s-xiawenc.git branch vlan_v3 https://gitorious.org/libvirt-cim/xiaxia347s-xiawenc/trees/vlan_v3 Wayne Xia (10): add source code of libbridge and libnl-3 building system modification for libnl3 and libbridge building system of libnetwork linking with libnl3 and libbridge libnetwork source code with a test program add a CIM model helper in libxkutil CIM model - Makefile change CIM model - VESS CIM model - VESSSD CIM model - EthernetPort CIM model - EASD Makefile.am | 14 +- configure.ac | 19 +- libnetwork/Makefile.am | 39 + libnetwork/dll_magic.h | 13 + libnetwork/host_network_API.c | 30 + libnetwork/host_network_API.h | 25 + libnetwork/host_network_basic.c | 657 ++++++ libnetwork/host_network_basic.h | 170 ++ libnetwork/host_network_error.h | 31 + libnetwork/host_network_helper.c | 659 ++++++ libnetwork/host_network_helper.h | 202 ++ libnetwork/host_network_implement_OSAPI.c | 453 ++++ libnetwork/host_network_implement_OSAPI.h | 21 + libnetwork/libbridge/.gitignore | 2 + libnetwork/libbridge/Makefile.am | 20 + libnetwork/libbridge/libbridge.h | 119 + libnetwork/libbridge/libbridge_devif.c | 442 ++++ libnetwork/libbridge/libbridge_if.c | 117 + libnetwork/libbridge/libbridge_init.c | 213 ++ libnetwork/libbridge/libbridge_misc.c | 51 + libnetwork/libbridge/libbridge_private.h | 56 + libnetwork/libnetwork_test.c | 82 + libnetwork/libnl3/Makefile.am | 8 + libnetwork/libnl3/include/Makefile.am | 122 + libnetwork/libnl3/include/linux/fib_rules.h | 69 + libnetwork/libnl3/include/linux/gen_stats.h | 67 + libnetwork/libnl3/include/linux/genetlink.h | 83 + libnetwork/libnl3/include/linux/if.h | 140 ++ libnetwork/libnl3/include/linux/if_addr.h | 55 + libnetwork/libnl3/include/linux/if_arp.h | 156 ++ libnetwork/libnl3/include/linux/if_ether.h | 125 ++ libnetwork/libnl3/include/linux/if_link.h | 377 ++++ libnetwork/libnl3/include/linux/if_vlan.h | 62 + libnetwork/libnl3/include/linux/inetdevice.h | 36 + libnetwork/libnl3/include/linux/ip_mp_alg.h | 22 + libnetwork/libnl3/include/linux/ipv6.h | 146 ++ libnetwork/libnl3/include/linux/neighbour.h | 155 ++ libnetwork/libnl3/include/linux/netfilter.h | 57 + .../libnl3/include/linux/netfilter/nfnetlink.h | 60 + .../include/linux/netfilter/nfnetlink_conntrack.h | 140 ++ .../libnl3/include/linux/netfilter/nfnetlink_log.h | 97 + .../include/linux/netfilter/nfnetlink_queue.h | 94 + libnetwork/libnl3/include/linux/netlink.h | 149 ++ libnetwork/libnl3/include/linux/pkt_cls.h | 467 ++++ libnetwork/libnl3/include/linux/pkt_sched.h | 606 +++++ libnetwork/libnl3/include/linux/rtnetlink.h | 605 +++++ libnetwork/libnl3/include/linux/snmp.h | 270 +++ .../libnl3/include/linux/tc_ematch/tc_em_meta.h | 89 + libnetwork/libnl3/include/netlink-generic.h | 20 + libnetwork/libnl3/include/netlink-local.h | 213 ++ libnetwork/libnl3/include/netlink-tc.h | 55 + libnetwork/libnl3/include/netlink-types.h | 846 +++++++ libnetwork/libnl3/include/netlink/addr.h | 66 + libnetwork/libnl3/include/netlink/attr.h | 283 +++ libnetwork/libnl3/include/netlink/cache-api.h | 230 ++ libnetwork/libnl3/include/netlink/cache.h | 134 ++ libnetwork/libnl3/include/netlink/cli/addr.h | 32 + libnetwork/libnl3/include/netlink/cli/class.h | 21 + libnetwork/libnl3/include/netlink/cli/cls.h | 24 + libnetwork/libnl3/include/netlink/cli/ct.h | 34 + libnetwork/libnl3/include/netlink/cli/link.h | 30 + libnetwork/libnl3/include/netlink/cli/neigh.h | 27 + libnetwork/libnl3/include/netlink/cli/qdisc.h | 23 + libnetwork/libnl3/include/netlink/cli/route.h | 34 + libnetwork/libnl3/include/netlink/cli/rule.h | 21 + libnetwork/libnl3/include/netlink/cli/tc.h | 39 + libnetwork/libnl3/include/netlink/cli/utils.h | 82 + libnetwork/libnl3/include/netlink/data.h | 41 + libnetwork/libnl3/include/netlink/errno.h | 64 + .../libnl3/include/netlink/fib_lookup/lookup.h | 42 + .../libnl3/include/netlink/fib_lookup/request.h | 51 + libnetwork/libnl3/include/netlink/genl/ctrl.h | 40 + libnetwork/libnl3/include/netlink/genl/family.h | 53 + libnetwork/libnl3/include/netlink/genl/genl.h | 46 + libnetwork/libnl3/include/netlink/genl/mngt.h | 87 + libnetwork/libnl3/include/netlink/handlers.h | 146 ++ libnetwork/libnl3/include/netlink/list.h | 93 + libnetwork/libnl3/include/netlink/msg.h | 147 ++ libnetwork/libnl3/include/netlink/netfilter/ct.h | 126 ++ libnetwork/libnl3/include/netlink/netfilter/log.h | 109 + .../libnl3/include/netlink/netfilter/log_msg.h | 98 + .../libnl3/include/netlink/netfilter/netfilter.h | 31 + libnetwork/libnl3/include/netlink/netfilter/nfnl.h | 44 + .../libnl3/include/netlink/netfilter/queue.h | 90 + .../libnl3/include/netlink/netfilter/queue_msg.h | 104 + libnetwork/libnl3/include/netlink/netlink-compat.h | 50 + libnetwork/libnl3/include/netlink/netlink-kernel.h | 293 +++ libnetwork/libnl3/include/netlink/netlink.h | 93 + libnetwork/libnl3/include/netlink/object-api.h | 348 +++ libnetwork/libnl3/include/netlink/object.h | 70 + libnetwork/libnl3/include/netlink/route/addr.h | 98 + libnetwork/libnl3/include/netlink/route/class.h | 66 + .../libnl3/include/netlink/route/classifier.h | 51 + .../libnl3/include/netlink/route/cls/basic.h | 31 + .../libnl3/include/netlink/route/cls/cgroup.h | 30 + .../libnl3/include/netlink/route/cls/ematch.h | 95 + .../libnl3/include/netlink/route/cls/ematch/cmp.h | 32 + .../libnl3/include/netlink/route/cls/ematch/meta.h | 41 + .../include/netlink/route/cls/ematch/nbyte.h | 36 + .../libnl3/include/netlink/route/cls/ematch/text.h | 42 + libnetwork/libnl3/include/netlink/route/cls/fw.h | 29 + .../libnl3/include/netlink/route/cls/police.h | 29 + libnetwork/libnl3/include/netlink/route/cls/u32.h | 43 + libnetwork/libnl3/include/netlink/route/link.h | 217 ++ libnetwork/libnl3/include/netlink/route/link/api.h | 134 ++ .../libnl3/include/netlink/route/link/bonding.h | 37 + .../libnl3/include/netlink/route/link/inet.h | 29 + .../libnl3/include/netlink/route/link/info-api.h | 20 + .../libnl3/include/netlink/route/link/vlan.h | 57 + .../libnl3/include/netlink/route/neighbour.h | 79 + libnetwork/libnl3/include/netlink/route/neightbl.h | 65 + libnetwork/libnl3/include/netlink/route/nexthop.h | 65 + libnetwork/libnl3/include/netlink/route/pktloc.h | 49 + libnetwork/libnl3/include/netlink/route/qdisc.h | 73 + .../libnl3/include/netlink/route/qdisc/cbq.h | 30 + .../libnl3/include/netlink/route/qdisc/dsmark.h | 41 + .../libnl3/include/netlink/route/qdisc/fifo.h | 28 + .../libnl3/include/netlink/route/qdisc/htb.h | 47 + .../libnl3/include/netlink/route/qdisc/netem.h | 75 + .../libnl3/include/netlink/route/qdisc/prio.h | 53 + .../libnl3/include/netlink/route/qdisc/red.h | 17 + .../libnl3/include/netlink/route/qdisc/sfq.h | 36 + .../libnl3/include/netlink/route/qdisc/tbf.h | 40 + libnetwork/libnl3/include/netlink/route/route.h | 124 + libnetwork/libnl3/include/netlink/route/rtnl.h | 69 + libnetwork/libnl3/include/netlink/route/rule.h | 75 + libnetwork/libnl3/include/netlink/route/tc-api.h | 143 ++ libnetwork/libnl3/include/netlink/route/tc.h | 105 + libnetwork/libnl3/include/netlink/socket.h | 69 + libnetwork/libnl3/include/netlink/types.h | 110 + libnetwork/libnl3/include/netlink/utils.h | 85 + libnetwork/libnl3/include/netlink/version.h | 28 + libnetwork/libnl3/include/netlink/version.h.in | 28 + libnetwork/libnl3/lib/Makefile.am | 99 + libnetwork/libnl3/lib/addr.c | 918 ++++++++ libnetwork/libnl3/lib/attr.c | 1213 ++++++++++ libnetwork/libnl3/lib/cache.c | 965 ++++++++ libnetwork/libnl3/lib/cache_mngr.c | 391 ++++ libnetwork/libnl3/lib/cache_mngt.c | 256 +++ libnetwork/libnl3/lib/cli/cls/basic.c | 93 + libnetwork/libnl3/lib/cli/cls/cgroup.c | 75 + libnetwork/libnl3/lib/cli/qdisc/bfifo.c | 83 + libnetwork/libnl3/lib/cli/qdisc/blackhole.c | 64 + libnetwork/libnl3/lib/cli/qdisc/htb.c | 203 ++ libnetwork/libnl3/lib/cli/qdisc/pfifo.c | 77 + libnetwork/libnl3/lib/data.c | 186 ++ libnetwork/libnl3/lib/defs.h | 85 + libnetwork/libnl3/lib/defs.h.in | 84 + libnetwork/libnl3/lib/error.c | 116 + libnetwork/libnl3/lib/fib_lookup/lookup.c | 348 +++ libnetwork/libnl3/lib/fib_lookup/request.c | 185 ++ libnetwork/libnl3/lib/genl/ctrl.c | 380 ++++ libnetwork/libnl3/lib/genl/family.c | 316 +++ libnetwork/libnl3/lib/genl/genl.c | 268 +++ libnetwork/libnl3/lib/genl/mngt.c | 273 +++ libnetwork/libnl3/lib/handlers.c | 395 ++++ libnetwork/libnl3/lib/msg.c | 1050 +++++++++ libnetwork/libnl3/lib/netfilter/ct.c | 601 +++++ libnetwork/libnl3/lib/netfilter/ct_obj.c | 785 +++++++ libnetwork/libnl3/lib/netfilter/log.c | 251 +++ libnetwork/libnl3/lib/netfilter/log_msg.c | 209 ++ libnetwork/libnl3/lib/netfilter/log_msg_obj.c | 458 ++++ libnetwork/libnl3/lib/netfilter/log_obj.c | 287 +++ libnetwork/libnl3/lib/netfilter/netfilter.c | 53 + libnetwork/libnl3/lib/netfilter/nfnl.c | 245 ++ libnetwork/libnl3/lib/netfilter/queue.c | 251 +++ libnetwork/libnl3/lib/netfilter/queue_msg.c | 284 +++ libnetwork/libnl3/lib/netfilter/queue_msg_obj.c | 492 ++++ libnetwork/libnl3/lib/netfilter/queue_obj.c | 215 ++ libnetwork/libnl3/lib/nl.c | 896 ++++++++ libnetwork/libnl3/lib/object.c | 395 ++++ libnetwork/libnl3/lib/route/addr.c | 1054 +++++++++ libnetwork/libnl3/lib/route/class.c | 473 ++++ libnetwork/libnl3/lib/route/classid.c | 441 ++++ libnetwork/libnl3/lib/route/cls.c | 441 ++++ libnetwork/libnl3/lib/route/cls/basic.c | 229 ++ libnetwork/libnl3/lib/route/cls/cgroup.c | 189 ++ libnetwork/libnl3/lib/route/cls/ematch.c | 701 ++++++ libnetwork/libnl3/lib/route/cls/ematch/cmp.c | 93 + libnetwork/libnl3/lib/route/cls/ematch/container.c | 41 + libnetwork/libnl3/lib/route/cls/ematch/meta.c | 334 +++ libnetwork/libnl3/lib/route/cls/ematch/nbyte.c | 139 ++ libnetwork/libnl3/lib/route/cls/ematch/text.c | 183 ++ libnetwork/libnl3/lib/route/cls/ematch_grammar.l | 162 ++ libnetwork/libnl3/lib/route/cls/ematch_syntax.y | 497 +++++ libnetwork/libnl3/lib/route/cls/fw.c | 190 ++ libnetwork/libnl3/lib/route/cls/police.c | 66 + libnetwork/libnl3/lib/route/cls/u32.c | 551 +++++ libnetwork/libnl3/lib/route/link.c | 2342 ++++++++++++++++++++ libnetwork/libnl3/lib/route/link/api.c | 316 +++ libnetwork/libnl3/lib/route/link/bonding.c | 217 ++ libnetwork/libnl3/lib/route/link/bridge.c | 83 + libnetwork/libnl3/lib/route/link/dummy.c | 40 + libnetwork/libnl3/lib/route/link/inet.c | 280 +++ libnetwork/libnl3/lib/route/link/inet6.c | 377 ++++ libnetwork/libnl3/lib/route/link/vlan.c | 565 +++++ libnetwork/libnl3/lib/route/neigh.c | 846 +++++++ libnetwork/libnl3/lib/route/neightbl.c | 815 +++++++ libnetwork/libnl3/lib/route/nexthop.c | 290 +++ libnetwork/libnl3/lib/route/pktloc.c | 260 +++ libnetwork/libnl3/lib/route/pktloc_grammar.l | 51 + libnetwork/libnl3/lib/route/pktloc_syntax.y | 103 + libnetwork/libnl3/lib/route/qdisc.c | 575 +++++ libnetwork/libnl3/lib/route/qdisc/blackhole.c | 37 + libnetwork/libnl3/lib/route/qdisc/cbq.c | 204 ++ libnetwork/libnl3/lib/route/qdisc/dsmark.c | 413 ++++ libnetwork/libnl3/lib/route/qdisc/fifo.c | 169 ++ libnetwork/libnl3/lib/route/qdisc/htb.c | 643 ++++++ libnetwork/libnl3/lib/route/qdisc/netem.c | 906 ++++++++ libnetwork/libnl3/lib/route/qdisc/prio.c | 294 +++ libnetwork/libnl3/lib/route/qdisc/red.c | 190 ++ libnetwork/libnl3/lib/route/qdisc/sfq.c | 256 +++ libnetwork/libnl3/lib/route/qdisc/tbf.c | 460 ++++ libnetwork/libnl3/lib/route/route.c | 202 ++ libnetwork/libnl3/lib/route/route_obj.c | 1148 ++++++++++ libnetwork/libnl3/lib/route/route_utils.c | 171 ++ libnetwork/libnl3/lib/route/rtnl.c | 124 + libnetwork/libnl3/lib/route/rule.c | 753 +++++++ libnetwork/libnl3/lib/route/tc.c | 1069 +++++++++ libnetwork/libnl3/lib/socket.c | 628 ++++++ libnetwork/libnl3/lib/stamp-h1 | 1 + libnetwork/libnl3/lib/utils.c | 1040 +++++++++ libxkutil/Makefile.am | 12 +- libxkutil/network_model_helper.c | 466 ++++ libxkutil/network_model_helper.h | 105 + schema/EthernetPort.mof | 4 + schema/EthernetPort.registration | 3 + schema/EthernetPortAllocationSettingData.mof | 21 + .../EthernetPortAllocationSettingData.registration | 3 + schema/VirtualEthernetSwitchSystem.mof | 10 + schema/VirtualEthernetSwitchSystem.registration | 3 + schema/VirtualEthernetSwitchSystemSettingData.mof | 27 + ...ualEthernetSwitchSystemSettingData.registration | 3 + src/Makefile.am | 23 +- src/Virt_EASD.c | 729 ++++++ src/Virt_EASD.h | 59 + src/Virt_EthernetPort.c | 561 +++++ src/Virt_EthernetPort.h | 58 + src/Virt_VESSSD.c | 372 ++++ src/Virt_VESSSD.h | 39 + src/Virt_VirtualEthernetSwitchSystem.c | 477 ++++ src/Virt_VirtualEthernetSwitchSystem.h | 52 + 242 files changed, 53037 insertions(+), 10 deletions(-) create mode 100644 libnetwork/Makefile.am create mode 100644 libnetwork/dll_magic.h create mode 100644 libnetwork/host_network_API.c create mode 100644 libnetwork/host_network_API.h create mode 100644 libnetwork/host_network_basic.c create mode 100644 libnetwork/host_network_basic.h create mode 100644 libnetwork/host_network_error.h create mode 100644 libnetwork/host_network_helper.c create mode 100644 libnetwork/host_network_helper.h create mode 100644 libnetwork/host_network_implement_OSAPI.c create mode 100644 libnetwork/host_network_implement_OSAPI.h create mode 100755 libnetwork/libbridge/.gitignore create mode 100644 libnetwork/libbridge/Makefile.am create mode 100644 libnetwork/libbridge/libbridge.h create mode 100644 libnetwork/libbridge/libbridge_devif.c create mode 100644 libnetwork/libbridge/libbridge_if.c create mode 100644 libnetwork/libbridge/libbridge_init.c create mode 100644 libnetwork/libbridge/libbridge_misc.c create mode 100644 libnetwork/libbridge/libbridge_private.h create mode 100644 libnetwork/libnetwork_test.c create mode 100644 libnetwork/libnl3/Makefile.am create mode 100644 libnetwork/libnl3/include/Makefile.am create mode 100644 libnetwork/libnl3/include/linux/fib_rules.h create mode 100644 libnetwork/libnl3/include/linux/gen_stats.h create mode 100644 libnetwork/libnl3/include/linux/genetlink.h create mode 100644 libnetwork/libnl3/include/linux/if.h create mode 100644 libnetwork/libnl3/include/linux/if_addr.h create mode 100644 libnetwork/libnl3/include/linux/if_arp.h create mode 100644 libnetwork/libnl3/include/linux/if_ether.h create mode 100644 libnetwork/libnl3/include/linux/if_link.h create mode 100644 libnetwork/libnl3/include/linux/if_vlan.h create mode 100644 libnetwork/libnl3/include/linux/inetdevice.h create mode 100644 libnetwork/libnl3/include/linux/ip_mp_alg.h create mode 100644 libnetwork/libnl3/include/linux/ipv6.h create mode 100644 libnetwork/libnl3/include/linux/neighbour.h create mode 100644 libnetwork/libnl3/include/linux/netfilter.h create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink.h create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink_conntrack.h create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink_log.h create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink_queue.h create mode 100644 libnetwork/libnl3/include/linux/netlink.h create mode 100644 libnetwork/libnl3/include/linux/pkt_cls.h create mode 100644 libnetwork/libnl3/include/linux/pkt_sched.h create mode 100644 libnetwork/libnl3/include/linux/rtnetlink.h create mode 100644 libnetwork/libnl3/include/linux/snmp.h create mode 100644 libnetwork/libnl3/include/linux/tc_ematch/tc_em_meta.h create mode 100644 libnetwork/libnl3/include/netlink-generic.h create mode 100644 libnetwork/libnl3/include/netlink-local.h create mode 100644 libnetwork/libnl3/include/netlink-tc.h create mode 100644 libnetwork/libnl3/include/netlink-types.h create mode 100644 libnetwork/libnl3/include/netlink/addr.h create mode 100644 libnetwork/libnl3/include/netlink/attr.h create mode 100644 libnetwork/libnl3/include/netlink/cache-api.h create mode 100644 libnetwork/libnl3/include/netlink/cache.h create mode 100644 libnetwork/libnl3/include/netlink/cli/addr.h create mode 100644 libnetwork/libnl3/include/netlink/cli/class.h create mode 100644 libnetwork/libnl3/include/netlink/cli/cls.h create mode 100644 libnetwork/libnl3/include/netlink/cli/ct.h create mode 100644 libnetwork/libnl3/include/netlink/cli/link.h create mode 100644 libnetwork/libnl3/include/netlink/cli/neigh.h create mode 100644 libnetwork/libnl3/include/netlink/cli/qdisc.h create mode 100644 libnetwork/libnl3/include/netlink/cli/route.h create mode 100644 libnetwork/libnl3/include/netlink/cli/rule.h create mode 100644 libnetwork/libnl3/include/netlink/cli/tc.h create mode 100644 libnetwork/libnl3/include/netlink/cli/utils.h create mode 100644 libnetwork/libnl3/include/netlink/data.h create mode 100644 libnetwork/libnl3/include/netlink/errno.h create mode 100644 libnetwork/libnl3/include/netlink/fib_lookup/lookup.h create mode 100644 libnetwork/libnl3/include/netlink/fib_lookup/request.h create mode 100644 libnetwork/libnl3/include/netlink/genl/ctrl.h create mode 100644 libnetwork/libnl3/include/netlink/genl/family.h create mode 100644 libnetwork/libnl3/include/netlink/genl/genl.h create mode 100644 libnetwork/libnl3/include/netlink/genl/mngt.h create mode 100644 libnetwork/libnl3/include/netlink/handlers.h create mode 100644 libnetwork/libnl3/include/netlink/list.h create mode 100644 libnetwork/libnl3/include/netlink/msg.h create mode 100644 libnetwork/libnl3/include/netlink/netfilter/ct.h create mode 100644 libnetwork/libnl3/include/netlink/netfilter/log.h create mode 100644 libnetwork/libnl3/include/netlink/netfilter/log_msg.h create mode 100644 libnetwork/libnl3/include/netlink/netfilter/netfilter.h create mode 100644 libnetwork/libnl3/include/netlink/netfilter/nfnl.h create mode 100644 libnetwork/libnl3/include/netlink/netfilter/queue.h create mode 100644 libnetwork/libnl3/include/netlink/netfilter/queue_msg.h create mode 100644 libnetwork/libnl3/include/netlink/netlink-compat.h create mode 100644 libnetwork/libnl3/include/netlink/netlink-kernel.h create mode 100644 libnetwork/libnl3/include/netlink/netlink.h create mode 100644 libnetwork/libnl3/include/netlink/object-api.h create mode 100644 libnetwork/libnl3/include/netlink/object.h create mode 100644 libnetwork/libnl3/include/netlink/route/addr.h create mode 100644 libnetwork/libnl3/include/netlink/route/class.h create mode 100644 libnetwork/libnl3/include/netlink/route/classifier.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/basic.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/cgroup.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch/cmp.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch/meta.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch/nbyte.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch/text.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/fw.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/police.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/u32.h create mode 100644 libnetwork/libnl3/include/netlink/route/link.h create mode 100644 libnetwork/libnl3/include/netlink/route/link/api.h create mode 100644 libnetwork/libnl3/include/netlink/route/link/bonding.h create mode 100644 libnetwork/libnl3/include/netlink/route/link/inet.h create mode 100644 libnetwork/libnl3/include/netlink/route/link/info-api.h create mode 100644 libnetwork/libnl3/include/netlink/route/link/vlan.h create mode 100644 libnetwork/libnl3/include/netlink/route/neighbour.h create mode 100644 libnetwork/libnl3/include/netlink/route/neightbl.h create mode 100644 libnetwork/libnl3/include/netlink/route/nexthop.h create mode 100644 libnetwork/libnl3/include/netlink/route/pktloc.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/cbq.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/dsmark.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/fifo.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/htb.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/netem.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/prio.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/red.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/sfq.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/tbf.h create mode 100644 libnetwork/libnl3/include/netlink/route/route.h create mode 100644 libnetwork/libnl3/include/netlink/route/rtnl.h create mode 100644 libnetwork/libnl3/include/netlink/route/rule.h create mode 100644 libnetwork/libnl3/include/netlink/route/tc-api.h create mode 100644 libnetwork/libnl3/include/netlink/route/tc.h create mode 100644 libnetwork/libnl3/include/netlink/socket.h create mode 100644 libnetwork/libnl3/include/netlink/types.h create mode 100644 libnetwork/libnl3/include/netlink/utils.h create mode 100644 libnetwork/libnl3/include/netlink/version.h create mode 100644 libnetwork/libnl3/include/netlink/version.h.in create mode 100644 libnetwork/libnl3/lib/Makefile.am create mode 100644 libnetwork/libnl3/lib/addr.c create mode 100644 libnetwork/libnl3/lib/attr.c create mode 100644 libnetwork/libnl3/lib/cache.c create mode 100644 libnetwork/libnl3/lib/cache_mngr.c create mode 100644 libnetwork/libnl3/lib/cache_mngt.c create mode 100644 libnetwork/libnl3/lib/cli/cls/.dirstamp create mode 100644 libnetwork/libnl3/lib/cli/cls/basic.c create mode 100644 libnetwork/libnl3/lib/cli/cls/cgroup.c create mode 100644 libnetwork/libnl3/lib/cli/qdisc/.dirstamp create mode 100644 libnetwork/libnl3/lib/cli/qdisc/bfifo.c create mode 100644 libnetwork/libnl3/lib/cli/qdisc/blackhole.c create mode 100644 libnetwork/libnl3/lib/cli/qdisc/htb.c create mode 100644 libnetwork/libnl3/lib/cli/qdisc/pfifo.c create mode 100644 libnetwork/libnl3/lib/data.c create mode 100644 libnetwork/libnl3/lib/defs.h create mode 100644 libnetwork/libnl3/lib/defs.h.in create mode 100644 libnetwork/libnl3/lib/error.c create mode 100644 libnetwork/libnl3/lib/fib_lookup/.dirstamp create mode 100644 libnetwork/libnl3/lib/fib_lookup/lookup.c create mode 100644 libnetwork/libnl3/lib/fib_lookup/request.c create mode 100644 libnetwork/libnl3/lib/genl/.dirstamp create mode 100644 libnetwork/libnl3/lib/genl/ctrl.c create mode 100644 libnetwork/libnl3/lib/genl/family.c create mode 100644 libnetwork/libnl3/lib/genl/genl.c create mode 100644 libnetwork/libnl3/lib/genl/mngt.c create mode 100644 libnetwork/libnl3/lib/handlers.c create mode 100644 libnetwork/libnl3/lib/msg.c create mode 100644 libnetwork/libnl3/lib/netfilter/.dirstamp create mode 100644 libnetwork/libnl3/lib/netfilter/ct.c create mode 100644 libnetwork/libnl3/lib/netfilter/ct_obj.c create mode 100644 libnetwork/libnl3/lib/netfilter/log.c create mode 100644 libnetwork/libnl3/lib/netfilter/log_msg.c create mode 100644 libnetwork/libnl3/lib/netfilter/log_msg_obj.c create mode 100644 libnetwork/libnl3/lib/netfilter/log_obj.c create mode 100644 libnetwork/libnl3/lib/netfilter/netfilter.c create mode 100644 libnetwork/libnl3/lib/netfilter/nfnl.c create mode 100644 libnetwork/libnl3/lib/netfilter/queue.c create mode 100644 libnetwork/libnl3/lib/netfilter/queue_msg.c create mode 100644 libnetwork/libnl3/lib/netfilter/queue_msg_obj.c create mode 100644 libnetwork/libnl3/lib/netfilter/queue_obj.c create mode 100644 libnetwork/libnl3/lib/nl.c create mode 100644 libnetwork/libnl3/lib/object.c create mode 100644 libnetwork/libnl3/lib/route/.dirstamp create mode 100644 libnetwork/libnl3/lib/route/addr.c create mode 100644 libnetwork/libnl3/lib/route/class.c create mode 100644 libnetwork/libnl3/lib/route/classid.c create mode 100644 libnetwork/libnl3/lib/route/cls.c create mode 100644 libnetwork/libnl3/lib/route/cls/.dirstamp create mode 100644 libnetwork/libnl3/lib/route/cls/basic.c create mode 100644 libnetwork/libnl3/lib/route/cls/cgroup.c create mode 100644 libnetwork/libnl3/lib/route/cls/ematch.c create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/.dirstamp create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/cmp.c create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/container.c create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/meta.c create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/nbyte.c create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/text.c create mode 100644 libnetwork/libnl3/lib/route/cls/ematch_grammar.l create mode 100644 libnetwork/libnl3/lib/route/cls/ematch_syntax.y create mode 100644 libnetwork/libnl3/lib/route/cls/fw.c create mode 100644 libnetwork/libnl3/lib/route/cls/police.c create mode 100644 libnetwork/libnl3/lib/route/cls/u32.c create mode 100644 libnetwork/libnl3/lib/route/link.c create mode 100644 libnetwork/libnl3/lib/route/link/.dirstamp create mode 100644 libnetwork/libnl3/lib/route/link/api.c create mode 100644 libnetwork/libnl3/lib/route/link/bonding.c create mode 100644 libnetwork/libnl3/lib/route/link/bridge.c create mode 100644 libnetwork/libnl3/lib/route/link/dummy.c create mode 100644 libnetwork/libnl3/lib/route/link/inet.c create mode 100644 libnetwork/libnl3/lib/route/link/inet6.c create mode 100644 libnetwork/libnl3/lib/route/link/vlan.c create mode 100644 libnetwork/libnl3/lib/route/neigh.c create mode 100644 libnetwork/libnl3/lib/route/neightbl.c create mode 100644 libnetwork/libnl3/lib/route/nexthop.c create mode 100644 libnetwork/libnl3/lib/route/pktloc.c create mode 100644 libnetwork/libnl3/lib/route/pktloc_grammar.l create mode 100644 libnetwork/libnl3/lib/route/pktloc_syntax.y create mode 100644 libnetwork/libnl3/lib/route/qdisc.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/.dirstamp create mode 100644 libnetwork/libnl3/lib/route/qdisc/blackhole.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/cbq.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/dsmark.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/fifo.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/htb.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/netem.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/prio.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/red.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/sfq.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/tbf.c create mode 100644 libnetwork/libnl3/lib/route/route.c create mode 100644 libnetwork/libnl3/lib/route/route_obj.c create mode 100644 libnetwork/libnl3/lib/route/route_utils.c create mode 100644 libnetwork/libnl3/lib/route/rtnl.c create mode 100644 libnetwork/libnl3/lib/route/rule.c create mode 100644 libnetwork/libnl3/lib/route/tc.c create mode 100644 libnetwork/libnl3/lib/socket.c create mode 100644 libnetwork/libnl3/lib/stamp-h1 create mode 100644 libnetwork/libnl3/lib/utils.c create mode 100644 libxkutil/network_model_helper.c create mode 100644 libxkutil/network_model_helper.h create mode 100644 schema/EthernetPort.mof create mode 100644 schema/EthernetPort.registration create mode 100644 schema/EthernetPortAllocationSettingData.mof create mode 100644 schema/EthernetPortAllocationSettingData.registration create mode 100644 schema/VirtualEthernetSwitchSystem.mof create mode 100644 schema/VirtualEthernetSwitchSystem.registration create mode 100644 schema/VirtualEthernetSwitchSystemSettingData.mof create mode 100644 schema/VirtualEthernetSwitchSystemSettingData.registration create mode 100644 src/Virt_EASD.c create mode 100644 src/Virt_EASD.h create mode 100644 src/Virt_EthernetPort.c create mode 100644 src/Virt_EthernetPort.h create mode 100644 src/Virt_VESSSD.c create mode 100644 src/Virt_VESSSD.h create mode 100644 src/Virt_VirtualEthernetSwitchSystem.c create mode 100644 src/Virt_VirtualEthernetSwitchSystem.h -- 1.7.6 From xiawenc at linux.vnet.ibm.com Thu Jan 12 09:46:47 2012 From: xiawenc at linux.vnet.ibm.com (Wayne Xia) Date: Thu, 12 Jan 2012 17:46:47 +0800 Subject: [Libvirt-cim] [V3 PATCH 03/10] building system of libnetwork linking with libnl3 and libbridge In-Reply-To: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1326361614-18674-4-git-send-email-xiawenc@linux.vnet.ibm.com> This is the building file that archive libnl3, libbridge and libnetwork itself's code into one dynamic library. Signed-off-by: Wayne Xia --- libnetwork/Makefile.am | 39 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 39 insertions(+), 0 deletions(-) create mode 100644 libnetwork/Makefile.am diff --git a/libnetwork/Makefile.am b/libnetwork/Makefile.am new file mode 100644 index 0000000..afba670 --- /dev/null +++ b/libnetwork/Makefile.am @@ -0,0 +1,39 @@ +# Copyright IBM Corp. 2011 +# Auther: +# Wenchao Xia, +# +# Try build a dynamic library libnetwork.so, which +# include libnl-3 and libbridge binaries. Doing this is +# because there is no devel-libbridge.rpm, and there are +# many program still using libnl1.so, which conflicts with +# libnl-3. +# Exported symbols are strictly limited by Macro DLL_PUBLIC +# to reduce name space polution. +# It need libcmpiutil to use CU_DEBUG facility. +# A test program is generated named as libnetwork_test. + +SUBDIRS = libbridge libnl3 + +LDFLAGS = $(LIBNETWORK_DEFINES) + +AM_CFLAGS = $(CFLAGS_STRICT) \ + -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" \ + $(LIBNETWORK_CFLAGS) $(LIBNETWORK_DEFINES) -I$(top_srcdir)/libnetwork/libnl3/include + + +noinst_HEADERS = host_network_API.h host_network_basic.h host_network_helper.h host_network_error.h \ + host_network_implement_OSAPI.h dll_magic.h + +lib_LTLIBRARIES = libnetwork.la + +libnetwork_la_SOURCES = host_network_API.c host_network_basic.c host_network_helper.c \ + host_network_implement_OSAPI.c +libnetwork_la_LDFLAGS = -version-info @VERSION_INFO@ -lcmpiutil +libnetwork_la_LIBADD = libbridge/libbridge.la \ + libnl3/lib/libnl-route-3-4cim.la + +noinst_PROGRAMS = libnetwork_test + +libnetwork_test_SOURCES = libnetwork_test.c +libnetwork_test_LDFLAGS = -lcmpiutil +libnetwork_test_LDADD = libnetwork.la -- 1.7.6 From xiawenc at linux.vnet.ibm.com Thu Jan 12 09:46:52 2012 From: xiawenc at linux.vnet.ibm.com (Wayne Xia) Date: Thu, 12 Jan 2012 17:46:52 +0800 Subject: [Libvirt-cim] [V3 PATCH 08/10] CIM model - VESSSD In-Reply-To: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1326361614-18674-9-git-send-email-xiawenc@linux.vnet.ibm.com> SettingData of VirtualEthernetSwitchSystem. Signed-off-by: Wayne Xia --- schema/VirtualEthernetSwitchSystemSettingData.mof | 27 ++ ...ualEthernetSwitchSystemSettingData.registration | 3 + src/Virt_VESSSD.c | 372 ++++++++++++++++++++ src/Virt_VESSSD.h | 39 ++ 4 files changed, 441 insertions(+), 0 deletions(-) create mode 100644 schema/VirtualEthernetSwitchSystemSettingData.mof create mode 100644 schema/VirtualEthernetSwitchSystemSettingData.registration create mode 100644 src/Virt_VESSSD.c create mode 100644 src/Virt_VESSSD.h diff --git a/schema/VirtualEthernetSwitchSystemSettingData.mof b/schema/VirtualEthernetSwitchSystemSettingData.mof new file mode 100644 index 0000000..81ef22a --- /dev/null +++ b/schema/VirtualEthernetSwitchSystemSettingData.mof @@ -0,0 +1,27 @@ +// Copyright IBM Corp. 2007 + + +/* fix me: the libvirt-cim lacks parent class + "VirtualEthernetSwitchSettingData" defined in DSP1050 */ +[Description ( + "A class derived from Virt_VirtualEthernetSystemSettingData to represent " + "the config of ."), + Provider("cmpi::Virt_VESSSD") +] +class Net_VirtualEthernetSwitchSystemSettingData : CIM_VirtualSystemSettingData +{ + + [Description ("Virtual Switch System type number")] + string VirtualSystemType; + + string AssociatedResourcePool; + + uint16 VLAN_Connection[]; + + uint16 MaxNumAddress; + + uint16 EVBMode; + + uint16 STP; + +}; diff --git a/schema/VirtualEthernetSwitchSystemSettingData.registration b/schema/VirtualEthernetSwitchSystemSettingData.registration new file mode 100644 index 0000000..14bfc30 --- /dev/null +++ b/schema/VirtualEthernetSwitchSystemSettingData.registration @@ -0,0 +1,3 @@ +# Copyright IBM Corp. 2011 +# Classname Namespace ProviderName ProviderModule ProviderTypes +Net_VirtualEthernetSwitchSystemSettingData root/virt Virt_VESSSD Virt_VESSSD instance diff --git a/src/Virt_VESSSD.c b/src/Virt_VESSSD.c new file mode 100644 index 0000000..f43eead --- /dev/null +++ b/src/Virt_VESSSD.c @@ -0,0 +1,372 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "cs_util.h" +#include "misc_util.h" +#include "device_parsing.h" + +#include "Virt_VESSSD.h" +#include "network_model_helper.h" + +static const CMPIBroker *_BROKER; + +static int set_primary_for_vesssd(const char *prefix, const CMPIBroker *broker, + EthIface *piface, CMPIInstance *instance) +{ + char *name, *vesssd_name; + int asret; + + if (piface->name == NULL) { + return 0; + } + + CMSetProperty(instance, "VirtualSystemType", + (CMPIValue *)"DMTF:VirtualEthernetSwitch", CMPI_chars); + + name = get_switch_name_from_iface(piface->name); + asret = asprintf(&vesssd_name, "%s:%s", prefix, name); + + CMSetProperty(instance, "InstanceID", + (CMPIValue *)vesssd_name, CMPI_chars); + CMSetProperty(instance, "ElementName", + (CMPIValue *)name, CMPI_chars); + CMSetProperty(instance, "VirtualSystemIdentifier", + (CMPIValue *)name, CMPI_chars); + CMSetProperty(instance, "VirtualSystemType", + (CMPIValue *)prefix, CMPI_chars); + + + + free(vesssd_name); + SAFE_FREE(name); + + return 1; +} + +static int set_secondary_for_vesssd(const CMPIBroker *broker, EthIface *piface, + CMPIInstance *instance) +{ + if ((piface->eth_type & ETH_TYPE_ETHER_ANY) && + (piface->eth_type & ETH_TYPE_ETHER_SUB_BRIDGE)) { + CMSetProperty(instance, "STP", + (CMPIValue *)&piface->pbr_prop->STP, CMPI_uint16); + } + + /* TODO add VLAN id discovery */ + return 1; +} + +/* Populate an instance with information from a switch */ +static CMPIStatus set_properties(const CMPIBroker *broker, + EthIface *piface, + const char *prefix, + CMPIInstance *instance) +{ + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; + char *errstr; + + if (!set_primary_for_vesssd(prefix, broker, piface, instance)) { + errstr = "failed to set primary properties for instance."; + CU_DEBUG("%s, iface name %s.", errstr, piface->name); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + if (!set_secondary_for_vesssd(broker, piface, instance)) { + errstr = "failed to set secondary properties for instance."; + CU_DEBUG("%s, iface name %s.", errstr, piface->name); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + cu_statusf(broker, &s, + CMPI_RC_OK, + ""); + + out: + return s; +} + +static CMPIStatus instance_from_vesssd(const CMPIBroker *broker, + const CMPIObjectPath *reference, + EthIface *piface, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + + inst = get_typed_instance(broker, + NETWORK_CLASS_PREFIX, + "VirtualEthernetSwitchSystemSettingData", + NAMESPACE(reference)); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to init SwitchSystem instance"); + goto out; + } + + s = set_properties(broker, + piface, + VESSD_SYSTEM_PREFIX, + inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + return s; +} + +CMPIStatus enum_vesssd(const CMPIBroker *broker, + const CMPIObjectPath *reference, + struct inst_list *plist) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + EthIfacesList ifaces_list; + int ret, i; + char *errstr; + + eth_ifaceslist_init(&ifaces_list); + + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_cim_switch, NULL); + + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + i = 0; + while (i < ifaces_list.count) { + CMPIInstance *inst = NULL; + + s = instance_from_vesssd(broker, + reference, + ifaces_list.pifaces[i], + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + inst_list_add(plist, inst); + i++; + } + + out: + eth_ifaceslist_uninit(&ifaces_list); + + return s; +} + +static CMPIStatus return_enum_vesssd(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const CMPIResult *results, + bool names_only) +{ + struct inst_list list; + CMPIStatus s = {CMPI_RC_OK, NULL}; + inst_list_init(&list); + + s = enum_vesssd(broker, reference, &list); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + if (names_only) { + cu_return_instance_names(results, &list); + } else { + cu_return_instances(results, &list); + } + out: + inst_list_free(&list); + return s; +} + +CMPIStatus get_vesssd_by_name(const CMPIBroker *broker, + const char *name, + const CMPIObjectPath *reference, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *eth_name = NULL; + char *errstr; + int ret; + EthIfacesList ifaces_list; + + eth_ifaceslist_init(&ifaces_list); + + eth_name = get_iface_name_from_switch(name); + if (eth_name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to convert switch_name"); + CU_DEBUG("switch name %s failed to convert.", name); + goto out; + } + + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_cim_switch_for_name, eth_name); + + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + if (ifaces_list.count != 1) { + errstr = "expected switch not found."; + CU_DEBUG("%s\n", errstr); + eth_ifaceslist_print(&ifaces_list); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + s = instance_from_vesssd(broker, + reference, + ifaces_list.pifaces[0], + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + eth_ifaceslist_uninit(&ifaces_list); + SAFE_FREE(eth_name); + return s; +} + +CMPIStatus get_vesssd_by_ref(const CMPIBroker *broker, + const CMPIObjectPath *reference, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *name = NULL; + + if ((!parse_instanceid(reference, NULL, &name)) || (name == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_FOUND, + "No such instance (InstanceID)"); + goto out; + } + + s = get_vesssd_by_name(broker, name, reference, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + s = cu_validate_ref(broker, reference, inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + free(name); + + return s; +} + +static CMPIStatus EnumInstanceNames(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference) +{ + return return_enum_vesssd(_BROKER, reference, results, true); +} + +static CMPIStatus EnumInstances(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const char **properties) +{ + return return_enum_vesssd(_BROKER, reference, results, false); +} + +static CMPIStatus GetInstance(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const char **properties) +{ + CMPIStatus s; + CMPIInstance *inst = NULL; + + s = get_vesssd_by_ref(_BROKER, reference, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + CMReturnInstance(results, inst); + + out: + return s; +} + +DEFAULT_CI(); +DEFAULT_MI(); +DEFAULT_DI(); +DEFAULT_EQ(); +DEFAULT_INST_CLEANUP(); + +STD_InstanceMIStub(, + Virt_VESSSD, + _BROKER, + libvirt_cim_init()); + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/Virt_VESSSD.h b/src/Virt_VESSSD.h new file mode 100644 index 0000000..5105057 --- /dev/null +++ b/src/Virt_VESSSD.h @@ -0,0 +1,39 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __VIRT_VESSSD_H +#define __VIRT_VESSSD_H + + +CMPIStatus enum_vesssd(const CMPIBroker *broker, + const CMPIObjectPath *reference, + struct inst_list *plist); + +CMPIStatus get_vesssd_by_ref(const CMPIBroker *broker, + const CMPIObjectPath *reference, + CMPIInstance **_inst); + +CMPIStatus get_vesssd_by_name(const CMPIBroker *broker, + const char *name, + const CMPIObjectPath *reference, + CMPIInstance **_inst); + + +#endif -- 1.7.6 From xiawenc at linux.vnet.ibm.com Thu Jan 12 09:46:45 2012 From: xiawenc at linux.vnet.ibm.com (Wayne Xia) Date: Thu, 12 Jan 2012 17:46:45 +0800 Subject: [Libvirt-cim] [V3 PATCH 01/10] add source code of libbridge and libnl-3 In-Reply-To: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1326361614-18674-2-git-send-email-xiawenc@linux.vnet.ibm.com> Libbridge comes from libbridge-util-1.5, which have no devel version released. Libnl3 have packages released, but most programs today such as libvirt still using libnl1.so, which conflict with libnl3 making runtime errors if libnl1.so and libnl-3.so were both loaded. To avoid this, the lib part of source code in libnl3 were directly moved here, and it would be compiled and encapsulated into libnetwork.so resulting isolation with libnl1.so. Source code version of libnl3 is libnl3.2.3. Signed-off-by: Wayne Xia --- libnetwork/libbridge/.gitignore | 2 + libnetwork/libbridge/libbridge.h | 119 + libnetwork/libbridge/libbridge_devif.c | 442 ++++ libnetwork/libbridge/libbridge_if.c | 117 + libnetwork/libbridge/libbridge_init.c | 213 ++ libnetwork/libbridge/libbridge_misc.c | 51 + libnetwork/libbridge/libbridge_private.h | 56 + libnetwork/libnl3/include/linux/fib_rules.h | 69 + libnetwork/libnl3/include/linux/gen_stats.h | 67 + libnetwork/libnl3/include/linux/genetlink.h | 83 + libnetwork/libnl3/include/linux/if.h | 140 ++ libnetwork/libnl3/include/linux/if_addr.h | 55 + libnetwork/libnl3/include/linux/if_arp.h | 156 ++ libnetwork/libnl3/include/linux/if_ether.h | 125 ++ libnetwork/libnl3/include/linux/if_link.h | 377 ++++ libnetwork/libnl3/include/linux/if_vlan.h | 62 + libnetwork/libnl3/include/linux/inetdevice.h | 36 + libnetwork/libnl3/include/linux/ip_mp_alg.h | 22 + libnetwork/libnl3/include/linux/ipv6.h | 146 ++ libnetwork/libnl3/include/linux/neighbour.h | 155 ++ libnetwork/libnl3/include/linux/netfilter.h | 57 + .../libnl3/include/linux/netfilter/nfnetlink.h | 60 + .../include/linux/netfilter/nfnetlink_conntrack.h | 140 ++ .../libnl3/include/linux/netfilter/nfnetlink_log.h | 97 + .../include/linux/netfilter/nfnetlink_queue.h | 94 + libnetwork/libnl3/include/linux/netlink.h | 149 ++ libnetwork/libnl3/include/linux/pkt_cls.h | 467 ++++ libnetwork/libnl3/include/linux/pkt_sched.h | 606 +++++ libnetwork/libnl3/include/linux/rtnetlink.h | 605 +++++ libnetwork/libnl3/include/linux/snmp.h | 270 +++ .../libnl3/include/linux/tc_ematch/tc_em_meta.h | 89 + libnetwork/libnl3/include/netlink-generic.h | 20 + libnetwork/libnl3/include/netlink-local.h | 213 ++ libnetwork/libnl3/include/netlink-tc.h | 55 + libnetwork/libnl3/include/netlink-types.h | 846 +++++++ libnetwork/libnl3/include/netlink/addr.h | 66 + libnetwork/libnl3/include/netlink/attr.h | 283 +++ libnetwork/libnl3/include/netlink/cache-api.h | 230 ++ libnetwork/libnl3/include/netlink/cache.h | 134 ++ libnetwork/libnl3/include/netlink/cli/addr.h | 32 + libnetwork/libnl3/include/netlink/cli/class.h | 21 + libnetwork/libnl3/include/netlink/cli/cls.h | 24 + libnetwork/libnl3/include/netlink/cli/ct.h | 34 + libnetwork/libnl3/include/netlink/cli/link.h | 30 + libnetwork/libnl3/include/netlink/cli/neigh.h | 27 + libnetwork/libnl3/include/netlink/cli/qdisc.h | 23 + libnetwork/libnl3/include/netlink/cli/route.h | 34 + libnetwork/libnl3/include/netlink/cli/rule.h | 21 + libnetwork/libnl3/include/netlink/cli/tc.h | 39 + libnetwork/libnl3/include/netlink/cli/utils.h | 82 + libnetwork/libnl3/include/netlink/data.h | 41 + libnetwork/libnl3/include/netlink/errno.h | 64 + .../libnl3/include/netlink/fib_lookup/lookup.h | 42 + .../libnl3/include/netlink/fib_lookup/request.h | 51 + libnetwork/libnl3/include/netlink/genl/ctrl.h | 40 + libnetwork/libnl3/include/netlink/genl/family.h | 53 + libnetwork/libnl3/include/netlink/genl/genl.h | 46 + libnetwork/libnl3/include/netlink/genl/mngt.h | 87 + libnetwork/libnl3/include/netlink/handlers.h | 146 ++ libnetwork/libnl3/include/netlink/list.h | 93 + libnetwork/libnl3/include/netlink/msg.h | 147 ++ libnetwork/libnl3/include/netlink/netfilter/ct.h | 126 ++ libnetwork/libnl3/include/netlink/netfilter/log.h | 109 + .../libnl3/include/netlink/netfilter/log_msg.h | 98 + .../libnl3/include/netlink/netfilter/netfilter.h | 31 + libnetwork/libnl3/include/netlink/netfilter/nfnl.h | 44 + .../libnl3/include/netlink/netfilter/queue.h | 90 + .../libnl3/include/netlink/netfilter/queue_msg.h | 104 + libnetwork/libnl3/include/netlink/netlink-compat.h | 50 + libnetwork/libnl3/include/netlink/netlink-kernel.h | 293 +++ libnetwork/libnl3/include/netlink/netlink.h | 93 + libnetwork/libnl3/include/netlink/object-api.h | 348 +++ libnetwork/libnl3/include/netlink/object.h | 70 + libnetwork/libnl3/include/netlink/route/addr.h | 98 + libnetwork/libnl3/include/netlink/route/class.h | 66 + .../libnl3/include/netlink/route/classifier.h | 51 + .../libnl3/include/netlink/route/cls/basic.h | 31 + .../libnl3/include/netlink/route/cls/cgroup.h | 30 + .../libnl3/include/netlink/route/cls/ematch.h | 95 + .../libnl3/include/netlink/route/cls/ematch/cmp.h | 32 + .../libnl3/include/netlink/route/cls/ematch/meta.h | 41 + .../include/netlink/route/cls/ematch/nbyte.h | 36 + .../libnl3/include/netlink/route/cls/ematch/text.h | 42 + libnetwork/libnl3/include/netlink/route/cls/fw.h | 29 + .../libnl3/include/netlink/route/cls/police.h | 29 + libnetwork/libnl3/include/netlink/route/cls/u32.h | 43 + libnetwork/libnl3/include/netlink/route/link.h | 217 ++ libnetwork/libnl3/include/netlink/route/link/api.h | 134 ++ .../libnl3/include/netlink/route/link/bonding.h | 37 + .../libnl3/include/netlink/route/link/inet.h | 29 + .../libnl3/include/netlink/route/link/info-api.h | 20 + .../libnl3/include/netlink/route/link/vlan.h | 57 + .../libnl3/include/netlink/route/neighbour.h | 79 + libnetwork/libnl3/include/netlink/route/neightbl.h | 65 + libnetwork/libnl3/include/netlink/route/nexthop.h | 65 + libnetwork/libnl3/include/netlink/route/pktloc.h | 49 + libnetwork/libnl3/include/netlink/route/qdisc.h | 73 + .../libnl3/include/netlink/route/qdisc/cbq.h | 30 + .../libnl3/include/netlink/route/qdisc/dsmark.h | 41 + .../libnl3/include/netlink/route/qdisc/fifo.h | 28 + .../libnl3/include/netlink/route/qdisc/htb.h | 47 + .../libnl3/include/netlink/route/qdisc/netem.h | 75 + .../libnl3/include/netlink/route/qdisc/prio.h | 53 + .../libnl3/include/netlink/route/qdisc/red.h | 17 + .../libnl3/include/netlink/route/qdisc/sfq.h | 36 + .../libnl3/include/netlink/route/qdisc/tbf.h | 40 + libnetwork/libnl3/include/netlink/route/route.h | 124 + libnetwork/libnl3/include/netlink/route/rtnl.h | 69 + libnetwork/libnl3/include/netlink/route/rule.h | 75 + libnetwork/libnl3/include/netlink/route/tc-api.h | 143 ++ libnetwork/libnl3/include/netlink/route/tc.h | 105 + libnetwork/libnl3/include/netlink/socket.h | 69 + libnetwork/libnl3/include/netlink/types.h | 110 + libnetwork/libnl3/include/netlink/utils.h | 85 + libnetwork/libnl3/include/netlink/version.h | 28 + libnetwork/libnl3/include/netlink/version.h.in | 28 + libnetwork/libnl3/lib/addr.c | 918 ++++++++ libnetwork/libnl3/lib/attr.c | 1213 ++++++++++ libnetwork/libnl3/lib/cache.c | 965 ++++++++ libnetwork/libnl3/lib/cache_mngr.c | 391 ++++ libnetwork/libnl3/lib/cache_mngt.c | 256 +++ libnetwork/libnl3/lib/cli/cls/basic.c | 93 + libnetwork/libnl3/lib/cli/cls/cgroup.c | 75 + libnetwork/libnl3/lib/cli/qdisc/bfifo.c | 83 + libnetwork/libnl3/lib/cli/qdisc/blackhole.c | 64 + libnetwork/libnl3/lib/cli/qdisc/htb.c | 203 ++ libnetwork/libnl3/lib/cli/qdisc/pfifo.c | 77 + libnetwork/libnl3/lib/data.c | 186 ++ libnetwork/libnl3/lib/defs.h | 85 + libnetwork/libnl3/lib/defs.h.in | 84 + libnetwork/libnl3/lib/error.c | 116 + libnetwork/libnl3/lib/fib_lookup/lookup.c | 348 +++ libnetwork/libnl3/lib/fib_lookup/request.c | 185 ++ libnetwork/libnl3/lib/genl/ctrl.c | 380 ++++ libnetwork/libnl3/lib/genl/family.c | 316 +++ libnetwork/libnl3/lib/genl/genl.c | 268 +++ libnetwork/libnl3/lib/genl/mngt.c | 273 +++ libnetwork/libnl3/lib/handlers.c | 395 ++++ libnetwork/libnl3/lib/msg.c | 1050 +++++++++ libnetwork/libnl3/lib/netfilter/ct.c | 601 +++++ libnetwork/libnl3/lib/netfilter/ct_obj.c | 785 +++++++ libnetwork/libnl3/lib/netfilter/log.c | 251 +++ libnetwork/libnl3/lib/netfilter/log_msg.c | 209 ++ libnetwork/libnl3/lib/netfilter/log_msg_obj.c | 458 ++++ libnetwork/libnl3/lib/netfilter/log_obj.c | 287 +++ libnetwork/libnl3/lib/netfilter/netfilter.c | 53 + libnetwork/libnl3/lib/netfilter/nfnl.c | 245 ++ libnetwork/libnl3/lib/netfilter/queue.c | 251 +++ libnetwork/libnl3/lib/netfilter/queue_msg.c | 284 +++ libnetwork/libnl3/lib/netfilter/queue_msg_obj.c | 492 ++++ libnetwork/libnl3/lib/netfilter/queue_obj.c | 215 ++ libnetwork/libnl3/lib/nl.c | 896 ++++++++ libnetwork/libnl3/lib/object.c | 395 ++++ libnetwork/libnl3/lib/route/addr.c | 1054 +++++++++ libnetwork/libnl3/lib/route/class.c | 473 ++++ libnetwork/libnl3/lib/route/classid.c | 441 ++++ libnetwork/libnl3/lib/route/cls.c | 441 ++++ libnetwork/libnl3/lib/route/cls/basic.c | 229 ++ libnetwork/libnl3/lib/route/cls/cgroup.c | 189 ++ libnetwork/libnl3/lib/route/cls/ematch.c | 701 ++++++ libnetwork/libnl3/lib/route/cls/ematch/cmp.c | 93 + libnetwork/libnl3/lib/route/cls/ematch/container.c | 41 + libnetwork/libnl3/lib/route/cls/ematch/meta.c | 334 +++ libnetwork/libnl3/lib/route/cls/ematch/nbyte.c | 139 ++ libnetwork/libnl3/lib/route/cls/ematch/text.c | 183 ++ libnetwork/libnl3/lib/route/cls/ematch_grammar.l | 162 ++ libnetwork/libnl3/lib/route/cls/ematch_syntax.y | 497 +++++ libnetwork/libnl3/lib/route/cls/fw.c | 190 ++ libnetwork/libnl3/lib/route/cls/police.c | 66 + libnetwork/libnl3/lib/route/cls/u32.c | 551 +++++ libnetwork/libnl3/lib/route/link.c | 2342 ++++++++++++++++++++ libnetwork/libnl3/lib/route/link/api.c | 316 +++ libnetwork/libnl3/lib/route/link/bonding.c | 217 ++ libnetwork/libnl3/lib/route/link/bridge.c | 83 + libnetwork/libnl3/lib/route/link/dummy.c | 40 + libnetwork/libnl3/lib/route/link/inet.c | 280 +++ libnetwork/libnl3/lib/route/link/inet6.c | 377 ++++ libnetwork/libnl3/lib/route/link/vlan.c | 565 +++++ libnetwork/libnl3/lib/route/neigh.c | 846 +++++++ libnetwork/libnl3/lib/route/neightbl.c | 815 +++++++ libnetwork/libnl3/lib/route/nexthop.c | 290 +++ libnetwork/libnl3/lib/route/pktloc.c | 260 +++ libnetwork/libnl3/lib/route/pktloc_grammar.l | 51 + libnetwork/libnl3/lib/route/pktloc_syntax.y | 103 + libnetwork/libnl3/lib/route/qdisc.c | 575 +++++ libnetwork/libnl3/lib/route/qdisc/blackhole.c | 37 + libnetwork/libnl3/lib/route/qdisc/cbq.c | 204 ++ libnetwork/libnl3/lib/route/qdisc/dsmark.c | 413 ++++ libnetwork/libnl3/lib/route/qdisc/fifo.c | 169 ++ libnetwork/libnl3/lib/route/qdisc/htb.c | 643 ++++++ libnetwork/libnl3/lib/route/qdisc/netem.c | 906 ++++++++ libnetwork/libnl3/lib/route/qdisc/prio.c | 294 +++ libnetwork/libnl3/lib/route/qdisc/red.c | 190 ++ libnetwork/libnl3/lib/route/qdisc/sfq.c | 256 +++ libnetwork/libnl3/lib/route/qdisc/tbf.c | 460 ++++ libnetwork/libnl3/lib/route/route.c | 202 ++ libnetwork/libnl3/lib/route/route_obj.c | 1148 ++++++++++ libnetwork/libnl3/lib/route/route_utils.c | 171 ++ libnetwork/libnl3/lib/route/rtnl.c | 124 + libnetwork/libnl3/lib/route/rule.c | 753 +++++++ libnetwork/libnl3/lib/route/tc.c | 1069 +++++++++ libnetwork/libnl3/lib/socket.c | 628 ++++++ libnetwork/libnl3/lib/stamp-h1 | 1 + libnetwork/libnl3/lib/utils.c | 1040 +++++++++ 204 files changed, 47356 insertions(+), 0 deletions(-) create mode 100755 libnetwork/libbridge/.gitignore create mode 100644 libnetwork/libbridge/libbridge.h create mode 100644 libnetwork/libbridge/libbridge_devif.c create mode 100644 libnetwork/libbridge/libbridge_if.c create mode 100644 libnetwork/libbridge/libbridge_init.c create mode 100644 libnetwork/libbridge/libbridge_misc.c create mode 100644 libnetwork/libbridge/libbridge_private.h create mode 100644 libnetwork/libnl3/include/linux/fib_rules.h create mode 100644 libnetwork/libnl3/include/linux/gen_stats.h create mode 100644 libnetwork/libnl3/include/linux/genetlink.h create mode 100644 libnetwork/libnl3/include/linux/if.h create mode 100644 libnetwork/libnl3/include/linux/if_addr.h create mode 100644 libnetwork/libnl3/include/linux/if_arp.h create mode 100644 libnetwork/libnl3/include/linux/if_ether.h create mode 100644 libnetwork/libnl3/include/linux/if_link.h create mode 100644 libnetwork/libnl3/include/linux/if_vlan.h create mode 100644 libnetwork/libnl3/include/linux/inetdevice.h create mode 100644 libnetwork/libnl3/include/linux/ip_mp_alg.h create mode 100644 libnetwork/libnl3/include/linux/ipv6.h create mode 100644 libnetwork/libnl3/include/linux/neighbour.h create mode 100644 libnetwork/libnl3/include/linux/netfilter.h create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink.h create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink_conntrack.h create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink_log.h create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink_queue.h create mode 100644 libnetwork/libnl3/include/linux/netlink.h create mode 100644 libnetwork/libnl3/include/linux/pkt_cls.h create mode 100644 libnetwork/libnl3/include/linux/pkt_sched.h create mode 100644 libnetwork/libnl3/include/linux/rtnetlink.h create mode 100644 libnetwork/libnl3/include/linux/snmp.h create mode 100644 libnetwork/libnl3/include/linux/tc_ematch/tc_em_meta.h create mode 100644 libnetwork/libnl3/include/netlink-generic.h create mode 100644 libnetwork/libnl3/include/netlink-local.h create mode 100644 libnetwork/libnl3/include/netlink-tc.h create mode 100644 libnetwork/libnl3/include/netlink-types.h create mode 100644 libnetwork/libnl3/include/netlink/addr.h create mode 100644 libnetwork/libnl3/include/netlink/attr.h create mode 100644 libnetwork/libnl3/include/netlink/cache-api.h create mode 100644 libnetwork/libnl3/include/netlink/cache.h create mode 100644 libnetwork/libnl3/include/netlink/cli/addr.h create mode 100644 libnetwork/libnl3/include/netlink/cli/class.h create mode 100644 libnetwork/libnl3/include/netlink/cli/cls.h create mode 100644 libnetwork/libnl3/include/netlink/cli/ct.h create mode 100644 libnetwork/libnl3/include/netlink/cli/link.h create mode 100644 libnetwork/libnl3/include/netlink/cli/neigh.h create mode 100644 libnetwork/libnl3/include/netlink/cli/qdisc.h create mode 100644 libnetwork/libnl3/include/netlink/cli/route.h create mode 100644 libnetwork/libnl3/include/netlink/cli/rule.h create mode 100644 libnetwork/libnl3/include/netlink/cli/tc.h create mode 100644 libnetwork/libnl3/include/netlink/cli/utils.h create mode 100644 libnetwork/libnl3/include/netlink/data.h create mode 100644 libnetwork/libnl3/include/netlink/errno.h create mode 100644 libnetwork/libnl3/include/netlink/fib_lookup/lookup.h create mode 100644 libnetwork/libnl3/include/netlink/fib_lookup/request.h create mode 100644 libnetwork/libnl3/include/netlink/genl/ctrl.h create mode 100644 libnetwork/libnl3/include/netlink/genl/family.h create mode 100644 libnetwork/libnl3/include/netlink/genl/genl.h create mode 100644 libnetwork/libnl3/include/netlink/genl/mngt.h create mode 100644 libnetwork/libnl3/include/netlink/handlers.h create mode 100644 libnetwork/libnl3/include/netlink/list.h create mode 100644 libnetwork/libnl3/include/netlink/msg.h create mode 100644 libnetwork/libnl3/include/netlink/netfilter/ct.h create mode 100644 libnetwork/libnl3/include/netlink/netfilter/log.h create mode 100644 libnetwork/libnl3/include/netlink/netfilter/log_msg.h create mode 100644 libnetwork/libnl3/include/netlink/netfilter/netfilter.h create mode 100644 libnetwork/libnl3/include/netlink/netfilter/nfnl.h create mode 100644 libnetwork/libnl3/include/netlink/netfilter/queue.h create mode 100644 libnetwork/libnl3/include/netlink/netfilter/queue_msg.h create mode 100644 libnetwork/libnl3/include/netlink/netlink-compat.h create mode 100644 libnetwork/libnl3/include/netlink/netlink-kernel.h create mode 100644 libnetwork/libnl3/include/netlink/netlink.h create mode 100644 libnetwork/libnl3/include/netlink/object-api.h create mode 100644 libnetwork/libnl3/include/netlink/object.h create mode 100644 libnetwork/libnl3/include/netlink/route/addr.h create mode 100644 libnetwork/libnl3/include/netlink/route/class.h create mode 100644 libnetwork/libnl3/include/netlink/route/classifier.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/basic.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/cgroup.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch/cmp.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch/meta.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch/nbyte.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch/text.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/fw.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/police.h create mode 100644 libnetwork/libnl3/include/netlink/route/cls/u32.h create mode 100644 libnetwork/libnl3/include/netlink/route/link.h create mode 100644 libnetwork/libnl3/include/netlink/route/link/api.h create mode 100644 libnetwork/libnl3/include/netlink/route/link/bonding.h create mode 100644 libnetwork/libnl3/include/netlink/route/link/inet.h create mode 100644 libnetwork/libnl3/include/netlink/route/link/info-api.h create mode 100644 libnetwork/libnl3/include/netlink/route/link/vlan.h create mode 100644 libnetwork/libnl3/include/netlink/route/neighbour.h create mode 100644 libnetwork/libnl3/include/netlink/route/neightbl.h create mode 100644 libnetwork/libnl3/include/netlink/route/nexthop.h create mode 100644 libnetwork/libnl3/include/netlink/route/pktloc.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/cbq.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/dsmark.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/fifo.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/htb.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/netem.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/prio.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/red.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/sfq.h create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/tbf.h create mode 100644 libnetwork/libnl3/include/netlink/route/route.h create mode 100644 libnetwork/libnl3/include/netlink/route/rtnl.h create mode 100644 libnetwork/libnl3/include/netlink/route/rule.h create mode 100644 libnetwork/libnl3/include/netlink/route/tc-api.h create mode 100644 libnetwork/libnl3/include/netlink/route/tc.h create mode 100644 libnetwork/libnl3/include/netlink/socket.h create mode 100644 libnetwork/libnl3/include/netlink/types.h create mode 100644 libnetwork/libnl3/include/netlink/utils.h create mode 100644 libnetwork/libnl3/include/netlink/version.h create mode 100644 libnetwork/libnl3/include/netlink/version.h.in create mode 100644 libnetwork/libnl3/lib/addr.c create mode 100644 libnetwork/libnl3/lib/attr.c create mode 100644 libnetwork/libnl3/lib/cache.c create mode 100644 libnetwork/libnl3/lib/cache_mngr.c create mode 100644 libnetwork/libnl3/lib/cache_mngt.c create mode 100644 libnetwork/libnl3/lib/cli/cls/.dirstamp create mode 100644 libnetwork/libnl3/lib/cli/cls/basic.c create mode 100644 libnetwork/libnl3/lib/cli/cls/cgroup.c create mode 100644 libnetwork/libnl3/lib/cli/qdisc/.dirstamp create mode 100644 libnetwork/libnl3/lib/cli/qdisc/bfifo.c create mode 100644 libnetwork/libnl3/lib/cli/qdisc/blackhole.c create mode 100644 libnetwork/libnl3/lib/cli/qdisc/htb.c create mode 100644 libnetwork/libnl3/lib/cli/qdisc/pfifo.c create mode 100644 libnetwork/libnl3/lib/data.c create mode 100644 libnetwork/libnl3/lib/defs.h create mode 100644 libnetwork/libnl3/lib/defs.h.in create mode 100644 libnetwork/libnl3/lib/error.c create mode 100644 libnetwork/libnl3/lib/fib_lookup/.dirstamp create mode 100644 libnetwork/libnl3/lib/fib_lookup/lookup.c create mode 100644 libnetwork/libnl3/lib/fib_lookup/request.c create mode 100644 libnetwork/libnl3/lib/genl/.dirstamp create mode 100644 libnetwork/libnl3/lib/genl/ctrl.c create mode 100644 libnetwork/libnl3/lib/genl/family.c create mode 100644 libnetwork/libnl3/lib/genl/genl.c create mode 100644 libnetwork/libnl3/lib/genl/mngt.c create mode 100644 libnetwork/libnl3/lib/handlers.c create mode 100644 libnetwork/libnl3/lib/msg.c create mode 100644 libnetwork/libnl3/lib/netfilter/.dirstamp create mode 100644 libnetwork/libnl3/lib/netfilter/ct.c create mode 100644 libnetwork/libnl3/lib/netfilter/ct_obj.c create mode 100644 libnetwork/libnl3/lib/netfilter/log.c create mode 100644 libnetwork/libnl3/lib/netfilter/log_msg.c create mode 100644 libnetwork/libnl3/lib/netfilter/log_msg_obj.c create mode 100644 libnetwork/libnl3/lib/netfilter/log_obj.c create mode 100644 libnetwork/libnl3/lib/netfilter/netfilter.c create mode 100644 libnetwork/libnl3/lib/netfilter/nfnl.c create mode 100644 libnetwork/libnl3/lib/netfilter/queue.c create mode 100644 libnetwork/libnl3/lib/netfilter/queue_msg.c create mode 100644 libnetwork/libnl3/lib/netfilter/queue_msg_obj.c create mode 100644 libnetwork/libnl3/lib/netfilter/queue_obj.c create mode 100644 libnetwork/libnl3/lib/nl.c create mode 100644 libnetwork/libnl3/lib/object.c create mode 100644 libnetwork/libnl3/lib/route/.dirstamp create mode 100644 libnetwork/libnl3/lib/route/addr.c create mode 100644 libnetwork/libnl3/lib/route/class.c create mode 100644 libnetwork/libnl3/lib/route/classid.c create mode 100644 libnetwork/libnl3/lib/route/cls.c create mode 100644 libnetwork/libnl3/lib/route/cls/.dirstamp create mode 100644 libnetwork/libnl3/lib/route/cls/basic.c create mode 100644 libnetwork/libnl3/lib/route/cls/cgroup.c create mode 100644 libnetwork/libnl3/lib/route/cls/ematch.c create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/.dirstamp create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/cmp.c create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/container.c create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/meta.c create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/nbyte.c create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/text.c create mode 100644 libnetwork/libnl3/lib/route/cls/ematch_grammar.l create mode 100644 libnetwork/libnl3/lib/route/cls/ematch_syntax.y create mode 100644 libnetwork/libnl3/lib/route/cls/fw.c create mode 100644 libnetwork/libnl3/lib/route/cls/police.c create mode 100644 libnetwork/libnl3/lib/route/cls/u32.c create mode 100644 libnetwork/libnl3/lib/route/link.c create mode 100644 libnetwork/libnl3/lib/route/link/.dirstamp create mode 100644 libnetwork/libnl3/lib/route/link/api.c create mode 100644 libnetwork/libnl3/lib/route/link/bonding.c create mode 100644 libnetwork/libnl3/lib/route/link/bridge.c create mode 100644 libnetwork/libnl3/lib/route/link/dummy.c create mode 100644 libnetwork/libnl3/lib/route/link/inet.c create mode 100644 libnetwork/libnl3/lib/route/link/inet6.c create mode 100644 libnetwork/libnl3/lib/route/link/vlan.c create mode 100644 libnetwork/libnl3/lib/route/neigh.c create mode 100644 libnetwork/libnl3/lib/route/neightbl.c create mode 100644 libnetwork/libnl3/lib/route/nexthop.c create mode 100644 libnetwork/libnl3/lib/route/pktloc.c create mode 100644 libnetwork/libnl3/lib/route/pktloc_grammar.l create mode 100644 libnetwork/libnl3/lib/route/pktloc_syntax.y create mode 100644 libnetwork/libnl3/lib/route/qdisc.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/.dirstamp create mode 100644 libnetwork/libnl3/lib/route/qdisc/blackhole.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/cbq.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/dsmark.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/fifo.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/htb.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/netem.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/prio.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/red.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/sfq.c create mode 100644 libnetwork/libnl3/lib/route/qdisc/tbf.c create mode 100644 libnetwork/libnl3/lib/route/route.c create mode 100644 libnetwork/libnl3/lib/route/route_obj.c create mode 100644 libnetwork/libnl3/lib/route/route_utils.c create mode 100644 libnetwork/libnl3/lib/route/rtnl.c create mode 100644 libnetwork/libnl3/lib/route/rule.c create mode 100644 libnetwork/libnl3/lib/route/tc.c create mode 100644 libnetwork/libnl3/lib/socket.c create mode 100644 libnetwork/libnl3/lib/stamp-h1 create mode 100644 libnetwork/libnl3/lib/utils.c diff --git a/libnetwork/libbridge/.gitignore b/libnetwork/libbridge/.gitignore new file mode 100755 index 0000000..f611548 --- /dev/null +++ b/libnetwork/libbridge/.gitignore @@ -0,0 +1,2 @@ +config.h +stamp-h1 diff --git a/libnetwork/libbridge/libbridge.h b/libnetwork/libbridge/libbridge.h new file mode 100644 index 0000000..39964f2 --- /dev/null +++ b/libnetwork/libbridge/libbridge.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2000 Lennert Buytenhek + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _LIBBRIDGE_H +#define _LIBBRIDGE_H + +#include +#include +#include + +/* defined in net/if.h but that conflicts with linux/if.h... */ +extern unsigned int if_nametoindex (const char *__ifname); +extern char *if_indextoname (unsigned int __ifindex, char *__ifname); + + +struct bridge_id +{ + unsigned char prio[2]; + unsigned char addr[6]; +}; + +struct bridge_info +{ + struct bridge_id designated_root; + struct bridge_id bridge_id; + unsigned root_path_cost; + struct timeval max_age; + struct timeval hello_time; + struct timeval forward_delay; + struct timeval bridge_max_age; + struct timeval bridge_hello_time; + struct timeval bridge_forward_delay; + u_int16_t root_port; + unsigned char stp_enabled; + unsigned char topology_change; + unsigned char topology_change_detected; + struct timeval ageing_time; + struct timeval hello_timer_value; + struct timeval tcn_timer_value; + struct timeval topology_change_timer_value; + struct timeval gc_timer_value; +}; + +struct fdb_entry +{ + u_int8_t mac_addr[6]; + u_int16_t port_no; + unsigned char is_local; + struct timeval ageing_timer_value; +}; + +struct port_info +{ + unsigned port_no; + struct bridge_id designated_root; + struct bridge_id designated_bridge; + u_int16_t port_id; + u_int16_t designated_port; + u_int8_t priority; + unsigned char top_change_ack; + unsigned char config_pending; + unsigned char state; + unsigned path_cost; + unsigned designated_cost; + struct timeval message_age_timer_value; + struct timeval forward_delay_timer_value; + struct timeval hold_timer_value; + unsigned char hairpin_mode; +}; + +extern int br_init(void); +extern int br_refresh(void); +extern void br_shutdown(void); + +extern int br_foreach_bridge(int (*iterator)(const char *brname, void *), + void *arg); +extern int br_foreach_port(const char *brname, + int (*iterator)(const char *brname, const char *port, + void *arg ), + void *arg); +extern const char *br_get_state_name(int state); + +extern int br_get_bridge_info(const char *br, struct bridge_info *info); +extern int br_get_port_info(const char *brname, const char *port, + struct port_info *info); +extern int br_add_bridge(const char *brname); +extern int br_del_bridge(const char *brname); +extern int br_add_interface(const char *br, const char *dev); +extern int br_del_interface(const char *br, const char *dev); +extern int br_set_bridge_forward_delay(const char *br, struct timeval *tv); +extern int br_set_bridge_hello_time(const char *br, struct timeval *tv); +extern int br_set_bridge_max_age(const char *br, struct timeval *tv); +extern int br_set_ageing_time(const char *br, struct timeval *tv); +extern int br_set_stp_state(const char *br, int stp_state); +extern int br_set_bridge_priority(const char *br, int bridge_priority); +extern int br_set_port_priority(const char *br, const char *p, + int port_priority); +extern int br_set_path_cost(const char *br, const char *p, + int path_cost); +extern int br_read_fdb(const char *br, struct fdb_entry *fdbs, + unsigned long skip, int num); +extern int br_set_hairpin_mode(const char *bridge, const char *dev, + int hairpin_mode); +#endif diff --git a/libnetwork/libbridge/libbridge_devif.c b/libnetwork/libbridge/libbridge_devif.c new file mode 100644 index 0000000..9d106f4 --- /dev/null +++ b/libnetwork/libbridge/libbridge_devif.c @@ -0,0 +1,442 @@ +/* + * Copyright (C) 2000 Lennert Buytenhek + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include "libbridge.h" +#include "libbridge_private.h" + +static FILE *fpopen(const char *dir, const char *name) +{ + char path[SYSFS_PATH_MAX]; + + snprintf(path, SYSFS_PATH_MAX, "%s/%s", dir, name); + return fopen(path, "r"); +} + +static void fetch_id(const char *dev, const char *name, struct bridge_id *id) +{ + FILE *f = fpopen(dev, name); + int unused; + + if (!f) + fprintf(stderr, "%s: %s\n", dev, strerror(errno)); + else { + unused = fscanf(f, "%2hhx%2hhx.%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", + &id->prio[0], &id->prio[1], + &id->addr[0], &id->addr[1], &id->addr[2], + &id->addr[3], &id->addr[4], &id->addr[5]); + fclose(f); + } +} + +/* Fetch an integer attribute out of sysfs. */ +static int fetch_int(const char *dev, const char *name) +{ + FILE *f = fpopen(dev, name); + int value = -1; + int unused; + + if (!f) + return 0; + + unused = fscanf(f, "%i", &value); + fclose(f); + return value; +} + +/* Get a time value out of sysfs */ +static void fetch_tv(const char *dev, const char *name, + struct timeval *tv) +{ + __jiffies_to_tv(tv, fetch_int(dev, name)); +} + +/* + * Convert device name to an index in the list of ports in bridge. + * + * Old API does bridge operations as if ports were an array + * inside bridge structure. + */ +static int get_portno(const char *brname, const char *ifname) +{ + int i; + int ifindex = if_nametoindex(ifname); + int ifindices[MAX_PORTS]; + unsigned long args[4] = { BRCTL_GET_PORT_LIST, + (unsigned long)ifindices, MAX_PORTS, 0 }; + struct ifreq ifr; + + if (ifindex <= 0) + goto error; + + memset(ifindices, 0, sizeof(ifindices)); + strncpy(ifr.ifr_name, brname, IFNAMSIZ); + ifr.ifr_data = (char *) &args; + + if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) { + dprintf("get_portno: get ports of %s failed: %s\n", + brname, strerror(errno)); + goto error; + } + + for (i = 0; i < MAX_PORTS; i++) { + if (ifindices[i] == ifindex) + return i; + } + + dprintf("%s is not a in bridge %s\n", ifname, brname); + error: + return -1; +} + +/* get information via ioctl */ +static int old_get_bridge_info(const char *bridge, struct bridge_info *info) +{ + struct ifreq ifr; + struct __bridge_info i; + unsigned long args[4] = { BRCTL_GET_BRIDGE_INFO, + (unsigned long) &i, 0, 0 }; + + memset(info, 0, sizeof(*info)); + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); + ifr.ifr_data = (char *) &args; + + if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) { + dprintf("%s: can't get info %s\n", + bridge, strerror(errno)); + return errno; + } + + memcpy(&info->designated_root, &i.designated_root, 8); + memcpy(&info->bridge_id, &i.bridge_id, 8); + info->root_path_cost = i.root_path_cost; + info->root_port = i.root_port; + info->topology_change = i.topology_change; + info->topology_change_detected = i.topology_change_detected; + info->stp_enabled = i.stp_enabled; + __jiffies_to_tv(&info->max_age, i.max_age); + __jiffies_to_tv(&info->hello_time, i.hello_time); + __jiffies_to_tv(&info->forward_delay, i.forward_delay); + __jiffies_to_tv(&info->bridge_max_age, i.bridge_max_age); + __jiffies_to_tv(&info->bridge_hello_time, i.bridge_hello_time); + __jiffies_to_tv(&info->bridge_forward_delay, i.bridge_forward_delay); + __jiffies_to_tv(&info->ageing_time, i.ageing_time); + __jiffies_to_tv(&info->hello_timer_value, i.hello_timer_value); + __jiffies_to_tv(&info->tcn_timer_value, i.tcn_timer_value); + __jiffies_to_tv(&info->topology_change_timer_value, + i.topology_change_timer_value); + __jiffies_to_tv(&info->gc_timer_value, i.gc_timer_value); + + return 0; +} + +/* + * Get bridge parameters using either sysfs or old + * ioctl. + */ +int br_get_bridge_info(const char *bridge, struct bridge_info *info) +{ + DIR *dir; + char path[SYSFS_PATH_MAX]; + + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge", bridge); + dir = opendir(path); + if (dir == NULL) { + dprintf("path '%s' is not a directory\n", path); + goto fallback; + } + + memset(info, 0, sizeof(*info)); + fetch_id(path, "root_id", &info->designated_root); + fetch_id(path, "bridge_id", &info->bridge_id); + info->root_path_cost = fetch_int(path, "root_path_cost"); + fetch_tv(path, "max_age", &info->max_age); + fetch_tv(path, "hello_time", &info->hello_time); + fetch_tv(path, "forward_delay", &info->forward_delay); + fetch_tv(path, "max_age", &info->bridge_max_age); + fetch_tv(path, "hello_time", &info->bridge_hello_time); + fetch_tv(path, "forward_delay", &info->bridge_forward_delay); + fetch_tv(path, "ageing_time", &info->ageing_time); + fetch_tv(path, "hello_timer", &info->hello_timer_value); + fetch_tv(path, "tcn_timer", &info->tcn_timer_value); + fetch_tv(path, "topology_change_timer", + &info->topology_change_timer_value);; + fetch_tv(path, "gc_timer", &info->gc_timer_value); + + info->root_port = fetch_int(path, "root_port"); + info->stp_enabled = fetch_int(path, "stp_state"); + info->topology_change = fetch_int(path, "topology_change"); + info->topology_change_detected = fetch_int(path, "topology_change_detected"); + + closedir(dir); + return 0; + +fallback: + return old_get_bridge_info(bridge, info); +} + +static int old_get_port_info(const char *brname, const char *port, + struct port_info *info) +{ + struct __port_info i; + int index; + + memset(info, 0, sizeof(*info)); + + index = get_portno(brname, port); + if (index < 0) + return errno; + + else { + struct ifreq ifr; + unsigned long args[4] = { BRCTL_GET_PORT_INFO, + (unsigned long) &i, index, 0 }; + + strncpy(ifr.ifr_name, brname, IFNAMSIZ); + ifr.ifr_data = (char *) &args; + + if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) { + dprintf("old can't get port %s(%d) info %s\n", + brname, index, strerror(errno)); + return errno; + } + } + + info->port_no = index; + memcpy(&info->designated_root, &i.designated_root, 8); + memcpy(&info->designated_bridge, &i.designated_bridge, 8); + info->port_id = i.port_id; + info->designated_port = i.designated_port; + info->path_cost = i.path_cost; + info->designated_cost = i.designated_cost; + info->state = i.state; + info->top_change_ack = i.top_change_ack; + info->config_pending = i.config_pending; + __jiffies_to_tv(&info->message_age_timer_value, + i.message_age_timer_value); + __jiffies_to_tv(&info->forward_delay_timer_value, + i.forward_delay_timer_value); + __jiffies_to_tv(&info->hold_timer_value, i.hold_timer_value); + info->hairpin_mode = 0; + return 0; +} + +/* + * Get information about port on bridge. + */ +int br_get_port_info(const char *brname, const char *port, + struct port_info *info) +{ + DIR *d; + char path[SYSFS_PATH_MAX]; + + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport", port); + d = opendir(path); + if (!d) + goto fallback; + + memset(info, 0, sizeof(*info)); + + fetch_id(path, "designated_root", &info->designated_root); + fetch_id(path, "designated_bridge", &info->designated_bridge); + info->port_no = fetch_int(path, "port_no"); + info->port_id = fetch_int(path, "port_id"); + info->designated_port = fetch_int(path, "designated_port"); + info->path_cost = fetch_int(path, "path_cost"); + info->designated_cost = fetch_int(path, "designated_cost"); + info->state = fetch_int(path, "state"); + info->top_change_ack = fetch_int(path, "change_ack"); + info->config_pending = fetch_int(path, "config_pending"); + fetch_tv(path, "message_age_timer", &info->message_age_timer_value); + fetch_tv(path, "forward_delay_timer", &info->forward_delay_timer_value); + fetch_tv(path, "hold_timer", &info->hold_timer_value); + info->hairpin_mode = fetch_int(path, "hairpin_mode"); + + closedir(d); + + return 0; +fallback: + return old_get_port_info(brname, port, info); +} + + +static int br_set(const char *bridge, const char *name, + unsigned long value, unsigned long oldcode) +{ + int ret; + char path[SYSFS_PATH_MAX]; + FILE *f; + + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/%s", bridge, name); + + f = fopen(path, "w"); + if (f) { + ret = fprintf(f, "%ld\n", value); + fclose(f); + } else { + /* fallback to old ioctl */ + struct ifreq ifr; + unsigned long args[4] = { oldcode, value, 0, 0 }; + + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); + ifr.ifr_data = (char *) &args; + ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + } + + return ret < 0 ? errno : 0; +} + +int br_set_bridge_forward_delay(const char *br, struct timeval *tv) +{ + return br_set(br, "forward_delay", __tv_to_jiffies(tv), + BRCTL_SET_BRIDGE_FORWARD_DELAY); +} + +int br_set_bridge_hello_time(const char *br, struct timeval *tv) +{ + return br_set(br, "hello_time", __tv_to_jiffies(tv), + BRCTL_SET_BRIDGE_HELLO_TIME); +} + +int br_set_bridge_max_age(const char *br, struct timeval *tv) +{ + return br_set(br, "max_age", __tv_to_jiffies(tv), + BRCTL_SET_BRIDGE_MAX_AGE); +} + +int br_set_ageing_time(const char *br, struct timeval *tv) +{ + return br_set(br, "ageing_time", __tv_to_jiffies(tv), + BRCTL_SET_AGEING_TIME); +} + +int br_set_stp_state(const char *br, int stp_state) +{ + return br_set(br, "stp_state", stp_state, BRCTL_SET_BRIDGE_STP_STATE); +} + +int br_set_bridge_priority(const char *br, int bridge_priority) +{ + return br_set(br, "priority", bridge_priority, + BRCTL_SET_BRIDGE_PRIORITY); +} + +static int port_set(const char *bridge, const char *ifname, + const char *name, unsigned long value, + unsigned long oldcode) +{ + int ret; + char path[SYSFS_PATH_MAX]; + FILE *f; + + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport/%s", ifname, name); + f = fopen(path, "w"); + if (f) { + ret = fprintf(f, "%ld\n", value); + fclose(f); + } else { + int index = get_portno(bridge, ifname); + + if (index < 0) + ret = index; + else { + struct ifreq ifr; + unsigned long args[4] = { oldcode, index, value, 0 }; + + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); + ifr.ifr_data = (char *) &args; + ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + } + } + + return ret < 0 ? errno : 0; +} + +int br_set_port_priority(const char *bridge, const char *port, int priority) +{ + return port_set(bridge, port, "priority", priority, BRCTL_SET_PORT_PRIORITY); +} + +int br_set_path_cost(const char *bridge, const char *port, int cost) +{ + return port_set(bridge, port, "path_cost", cost, BRCTL_SET_PATH_COST); +} + +int br_set_hairpin_mode(const char *bridge, const char *port, int hairpin_mode) +{ + return port_set(bridge, port, "hairpin_mode", hairpin_mode, 0); +} + +static inline void __copy_fdb(struct fdb_entry *ent, + const struct __fdb_entry *f) +{ + memcpy(ent->mac_addr, f->mac_addr, 6); + ent->port_no = f->port_no; + ent->is_local = f->is_local; + __jiffies_to_tv(&ent->ageing_timer_value, f->ageing_timer_value); +} + +int br_read_fdb(const char *bridge, struct fdb_entry *fdbs, + unsigned long offset, int num) +{ + FILE *f; + int i, n; + struct __fdb_entry fe[num]; + char path[SYSFS_PATH_MAX]; + + /* open /sys/class/net/brXXX/brforward */ + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brforward", bridge); + f = fopen(path, "r"); + if (f) { + fseek(f, offset*sizeof(struct __fdb_entry), SEEK_SET); + n = fread(fe, sizeof(struct __fdb_entry), num, f); + fclose(f); + } else { + /* old kernel, use ioctl */ + unsigned long args[4] = { BRCTL_GET_FDB_ENTRIES, + (unsigned long) fe, + num, offset }; + struct ifreq ifr; + int retries = 0; + + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); + ifr.ifr_data = (char *) args; + + retry: + n = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + + /* table can change during ioctl processing */ + if (n < 0 && errno == EAGAIN && ++retries < 10) { + sleep(0); + goto retry; + } + } + + for (i = 0; i < n; i++) + __copy_fdb(fdbs+i, fe+i); + + return n; +} diff --git a/libnetwork/libbridge/libbridge_if.c b/libnetwork/libbridge/libbridge_if.c new file mode 100644 index 0000000..77d3f8a --- /dev/null +++ b/libnetwork/libbridge/libbridge_if.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2000 Lennert Buytenhek + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "libbridge.h" +#include "libbridge_private.h" + + +int br_add_bridge(const char *brname) +{ + int ret; + +#ifdef SIOCBRADDBR + ret = ioctl(br_socket_fd, SIOCBRADDBR, brname); + if (ret < 0) +#endif + { + char _br[IFNAMSIZ]; + unsigned long arg[3] + = { BRCTL_ADD_BRIDGE, (unsigned long) _br }; + + strncpy(_br, brname, IFNAMSIZ); + ret = ioctl(br_socket_fd, SIOCSIFBR, arg); + } + + return ret < 0 ? errno : 0; +} + +int br_del_bridge(const char *brname) +{ + int ret; + +#ifdef SIOCBRDELBR + ret = ioctl(br_socket_fd, SIOCBRDELBR, brname); + if (ret < 0) +#endif + { + char _br[IFNAMSIZ]; + unsigned long arg[3] + = { BRCTL_DEL_BRIDGE, (unsigned long) _br }; + + strncpy(_br, brname, IFNAMSIZ); + ret = ioctl(br_socket_fd, SIOCSIFBR, arg); + } + return ret < 0 ? errno : 0; +} + +int br_add_interface(const char *bridge, const char *dev) +{ + struct ifreq ifr; + int err; + int ifindex = if_nametoindex(dev); + + if (ifindex == 0) + return ENODEV; + + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); +#ifdef SIOCBRADDIF + ifr.ifr_ifindex = ifindex; + err = ioctl(br_socket_fd, SIOCBRADDIF, &ifr); + if (err < 0) +#endif + { + unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 }; + + ifr.ifr_data = (char *) args; + err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + } + + return err < 0 ? errno : 0; +} + +int br_del_interface(const char *bridge, const char *dev) +{ + struct ifreq ifr; + int err; + int ifindex = if_nametoindex(dev); + + if (ifindex == 0) + return ENODEV; + + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); +#ifdef SIOCBRDELIF + ifr.ifr_ifindex = ifindex; + err = ioctl(br_socket_fd, SIOCBRDELIF, &ifr); + if (err < 0) +#endif + { + unsigned long args[4] = { BRCTL_DEL_IF, ifindex, 0, 0 }; + + ifr.ifr_data = (char *) args; + err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + } + + return err < 0 ? errno : 0; +} diff --git a/libnetwork/libbridge/libbridge_init.c b/libnetwork/libbridge/libbridge_init.c new file mode 100644 index 0000000..1c1acbd --- /dev/null +++ b/libnetwork/libbridge/libbridge_init.c @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2000 Lennert Buytenhek + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libbridge.h" +#include "libbridge_private.h" + +int br_socket_fd = -1; + +int br_init(void) +{ + if ((br_socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) + return errno; + return 0; +} + +void br_shutdown(void) +{ + close(br_socket_fd); + br_socket_fd = -1; +} + +/* If /sys/class/net/XXX/bridge exists then it must be a bridge */ +static int isbridge(const struct dirent *entry) +{ + char path[SYSFS_PATH_MAX]; + struct stat st; + + if (entry->d_name[0] == '.') + return 0; + + snprintf(path, SYSFS_PATH_MAX, + SYSFS_CLASS_NET "%s/bridge", entry->d_name); + return stat(path, &st) == 0 && S_ISDIR(st.st_mode); +} + +/* + * New interface uses sysfs to find bridges + */ +static int new_foreach_bridge(int (*iterator)(const char *name, void *), + void *arg) +{ + struct dirent **namelist; + int i, count = 0; + + count = scandir(SYSFS_CLASS_NET, &namelist, isbridge, alphasort); + if (count < 0) + return -1; + + for (i = 0; i < count; i++) { + if (iterator(namelist[i]->d_name, arg)) + break; + } + + for (i = 0; i < count; i++) + free(namelist[i]); + free(namelist); + + return count; +} + +/* + * Old interface uses ioctl + */ +static int old_foreach_bridge(int (*iterator)(const char *, void *), + void *iarg) +{ + int i, ret=0, num; + char ifname[IFNAMSIZ]; + int ifindices[MAX_BRIDGES]; + unsigned long args[3] = { BRCTL_GET_BRIDGES, + (unsigned long)ifindices, MAX_BRIDGES }; + + num = ioctl(br_socket_fd, SIOCGIFBR, args); + if (num < 0) { + dprintf("Get bridge indices failed: %s\n", + strerror(errno)); + return -errno; + } + + for (i = 0; i < num; i++) { + if (!if_indextoname(ifindices[i], ifname)) { + dprintf("get find name for ifindex %d\n", + ifindices[i]); + return -errno; + } + + ++ret; + if(iterator(ifname, iarg)) + break; + + } + + return ret; + +} + +/* + * Go over all bridges and call iterator function. + * if iterator returns non-zero then stop. + */ +int br_foreach_bridge(int (*iterator)(const char *, void *), + void *arg) +{ + int ret; + + ret = new_foreach_bridge(iterator, arg); + if (ret <= 0) + ret = old_foreach_bridge(iterator, arg); + + return ret; +} + +/* + * Only used if sysfs is not available. + */ +static int old_foreach_port(const char *brname, + int (*iterator)(const char *br, const char *port, + void *arg), + void *arg) +{ + int i, err, count; + struct ifreq ifr; + char ifname[IFNAMSIZ]; + int ifindices[MAX_PORTS]; + unsigned long args[4] = { BRCTL_GET_PORT_LIST, + (unsigned long)ifindices, MAX_PORTS, 0 }; + + memset(ifindices, 0, sizeof(ifindices)); + strncpy(ifr.ifr_name, brname, IFNAMSIZ); + ifr.ifr_data = (char *) &args; + + err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + if (err < 0) { + dprintf("list ports for bridge:'%s' failed: %s\n", + brname, strerror(errno)); + return -errno; + } + + count = 0; + for (i = 0; i < MAX_PORTS; i++) { + if (!ifindices[i]) + continue; + + if (!if_indextoname(ifindices[i], ifname)) { + dprintf("can't find name for ifindex:%d\n", + ifindices[i]); + continue; + } + + ++count; + if (iterator(brname, ifname, arg)) + break; + } + + return count; +} + +/* + * Iterate over all ports in bridge (using sysfs). + */ +int br_foreach_port(const char *brname, + int (*iterator)(const char *br, const char *port, void *arg), + void *arg) +{ + int i, count; + struct dirent **namelist; + char path[SYSFS_PATH_MAX]; + + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brif", brname); + count = scandir(path, &namelist, 0, alphasort); + if (count < 0) + return old_foreach_port(brname, iterator, arg); + + for (i = 0; i < count; i++) { + if (namelist[i]->d_name[0] == '.' + && (namelist[i]->d_name[1] == '\0' + || (namelist[i]->d_name[1] == '.' + && namelist[i]->d_name[2] == '\0'))) + continue; + + if (iterator(brname, namelist[i]->d_name, arg)) + break; + } + for (i = 0; i < count; i++) + free(namelist[i]); + free(namelist); + + return count; +} diff --git a/libnetwork/libbridge/libbridge_misc.c b/libnetwork/libbridge/libbridge_misc.c new file mode 100644 index 0000000..3420359 --- /dev/null +++ b/libnetwork/libbridge/libbridge_misc.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2000 Lennert Buytenhek + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include "libbridge.h" +#include "libbridge_private.h" + + +static const char *state_names[5] = { + [BR_STATE_DISABLED] = "disabled", + [BR_STATE_LISTENING] = "listening", + [BR_STATE_LEARNING] = "learning", + [BR_STATE_FORWARDING] = "forwarding", + [BR_STATE_BLOCKING] = "blocking", +}; + +const char *br_get_state_name(int state) +{ + if (state >= 0 && state <= 4) + return state_names[state]; + + return ""; +} + +int __br_hz_internal; + +int __get_hz(void); +int __get_hz(void) +{ + const char * s = getenv("HZ"); + return s ? atoi(s) : HZ; +} diff --git a/libnetwork/libbridge/libbridge_private.h b/libnetwork/libbridge/libbridge_private.h new file mode 100644 index 0000000..c5c4ce8 --- /dev/null +++ b/libnetwork/libbridge/libbridge_private.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2000 Lennert Buytenhek + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _LIBBRIDGE_PRIVATE_H +#define _LIBBRIDGE_PRIVATE_H + +//#include "config.h" + +#include +#include +#include +#include + +#define MAX_BRIDGES 1024 +#define MAX_PORTS 1024 + +#define SYSFS_CLASS_NET "/sys/class/net/" +#define SYSFS_PATH_MAX 256 + +#define dprintf(fmt,arg...) + +extern int br_socket_fd; + +static inline unsigned long __tv_to_jiffies(const struct timeval *tv) +{ + unsigned long long jif; + + jif = 1000000ULL * tv->tv_sec + tv->tv_usec; + + return jif/10000; +} + +static inline void __jiffies_to_tv(struct timeval *tv, unsigned long jiffies) +{ + unsigned long long tvusec; + + tvusec = 10000ULL*jiffies; + tv->tv_sec = tvusec/1000000; + tv->tv_usec = tvusec - 1000000 * tv->tv_sec; +} +#endif diff --git a/libnetwork/libnl3/include/linux/fib_rules.h b/libnetwork/libnl3/include/linux/fib_rules.h new file mode 100644 index 0000000..ed4504a --- /dev/null +++ b/libnetwork/libnl3/include/linux/fib_rules.h @@ -0,0 +1,69 @@ +#ifndef __LINUX_FIB_RULES_H +#define __LINUX_FIB_RULES_H + +/* rule is permanent, and cannot be deleted */ +#define FIB_RULE_PERMANENT 0x00000001 +#define FIB_RULE_INVERT 0x00000002 +#define FIB_RULE_UNRESOLVED 0x00000004 +#define FIB_RULE_IIF_DETACHED 0x00000008 +#define FIB_RULE_DEV_DETACHED FIB_RULE_IIF_DETACHED +#define FIB_RULE_OIF_DETACHED 0x00000010 + +/* try to find source address in routing lookups */ +#define FIB_RULE_FIND_SADDR 0x00010000 + +struct fib_rule_hdr { + __u8 family; + __u8 dst_len; + __u8 src_len; + __u8 tos; + + __u8 table; + __u8 res1; /* reserved */ + __u8 res2; /* reserved */ + __u8 action; + + __u32 flags; +}; + +enum { + FRA_UNSPEC, + FRA_DST, /* destination address */ + FRA_SRC, /* source address */ + FRA_IIFNAME, /* interface name */ +#define FRA_IFNAME FRA_IIFNAME + FRA_GOTO, /* target to jump to (FR_ACT_GOTO) */ + FRA_UNUSED2, + FRA_PRIORITY, /* priority/preference */ + FRA_UNUSED3, + FRA_UNUSED4, + FRA_UNUSED5, + FRA_FWMARK, /* mark */ + FRA_FLOW, /* flow/class id */ + FRA_UNUSED6, + FRA_UNUSED7, + FRA_UNUSED8, + FRA_TABLE, /* Extended table id */ + FRA_FWMASK, /* mask for netfilter mark */ + FRA_OIFNAME, + __FRA_MAX +}; + +#define FRA_MAX (__FRA_MAX - 1) + +enum { + FR_ACT_UNSPEC, + FR_ACT_TO_TBL, /* Pass to fixed table */ + FR_ACT_GOTO, /* Jump to another rule */ + FR_ACT_NOP, /* No operation */ + FR_ACT_RES3, + FR_ACT_RES4, + FR_ACT_BLACKHOLE, /* Drop without notification */ + FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */ + FR_ACT_PROHIBIT, /* Drop with EACCES */ + __FR_ACT_MAX, +}; + +#define FR_ACT_MAX (__FR_ACT_MAX - 1) + +#endif diff --git a/libnetwork/libnl3/include/linux/gen_stats.h b/libnetwork/libnl3/include/linux/gen_stats.h new file mode 100644 index 0000000..552c8a0 --- /dev/null +++ b/libnetwork/libnl3/include/linux/gen_stats.h @@ -0,0 +1,67 @@ +#ifndef __LINUX_GEN_STATS_H +#define __LINUX_GEN_STATS_H + +#include + +enum { + TCA_STATS_UNSPEC, + TCA_STATS_BASIC, + TCA_STATS_RATE_EST, + TCA_STATS_QUEUE, + TCA_STATS_APP, + __TCA_STATS_MAX, +}; +#define TCA_STATS_MAX (__TCA_STATS_MAX - 1) + +/** + * struct gnet_stats_basic - byte/packet throughput statistics + * @bytes: number of seen bytes + * @packets: number of seen packets + */ +struct gnet_stats_basic { + __u64 bytes; + __u32 packets; +}; +struct gnet_stats_basic_packed { + __u64 bytes; + __u32 packets; +} __attribute__ ((packed)); + +/** + * struct gnet_stats_rate_est - rate estimator + * @bps: current byte rate + * @pps: current packet rate + */ +struct gnet_stats_rate_est { + __u32 bps; + __u32 pps; +}; + +/** + * struct gnet_stats_queue - queuing statistics + * @qlen: queue length + * @backlog: backlog size of queue + * @drops: number of dropped packets + * @requeues: number of requeues + * @overlimits: number of enqueues over the limit + */ +struct gnet_stats_queue { + __u32 qlen; + __u32 backlog; + __u32 drops; + __u32 requeues; + __u32 overlimits; +}; + +/** + * struct gnet_estimator - rate estimator configuration + * @interval: sampling period + * @ewma_log: the log of measurement window weight + */ +struct gnet_estimator { + signed char interval; + unsigned char ewma_log; +}; + + +#endif /* __LINUX_GEN_STATS_H */ diff --git a/libnetwork/libnl3/include/linux/genetlink.h b/libnetwork/libnl3/include/linux/genetlink.h new file mode 100644 index 0000000..b834ef6 --- /dev/null +++ b/libnetwork/libnl3/include/linux/genetlink.h @@ -0,0 +1,83 @@ +#ifndef __LINUX_GENERIC_NETLINK_H +#define __LINUX_GENERIC_NETLINK_H + +#include +#include + +#define GENL_NAMSIZ 16 /* length of family name */ + +#define GENL_MIN_ID NLMSG_MIN_TYPE +#define GENL_MAX_ID 1023 + +struct genlmsghdr { + __u8 cmd; + __u8 version; + __u16 reserved; +}; + +#define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr)) + +#define GENL_ADMIN_PERM 0x01 +#define GENL_CMD_CAP_DO 0x02 +#define GENL_CMD_CAP_DUMP 0x04 +#define GENL_CMD_CAP_HASPOL 0x08 + +/* + * List of reserved static generic netlink identifiers: + */ +#define GENL_ID_GENERATE 0 +#define GENL_ID_CTRL NLMSG_MIN_TYPE + +/************************************************************************** + * Controller + **************************************************************************/ + +enum { + CTRL_CMD_UNSPEC, + CTRL_CMD_NEWFAMILY, + CTRL_CMD_DELFAMILY, + CTRL_CMD_GETFAMILY, + CTRL_CMD_NEWOPS, + CTRL_CMD_DELOPS, + CTRL_CMD_GETOPS, + CTRL_CMD_NEWMCAST_GRP, + CTRL_CMD_DELMCAST_GRP, + CTRL_CMD_GETMCAST_GRP, /* unused */ + __CTRL_CMD_MAX, +}; + +#define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1) + +enum { + CTRL_ATTR_UNSPEC, + CTRL_ATTR_FAMILY_ID, + CTRL_ATTR_FAMILY_NAME, + CTRL_ATTR_VERSION, + CTRL_ATTR_HDRSIZE, + CTRL_ATTR_MAXATTR, + CTRL_ATTR_OPS, + CTRL_ATTR_MCAST_GROUPS, + __CTRL_ATTR_MAX, +}; + +#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1) + +enum { + CTRL_ATTR_OP_UNSPEC, + CTRL_ATTR_OP_ID, + CTRL_ATTR_OP_FLAGS, + __CTRL_ATTR_OP_MAX, +}; + +#define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1) + +enum { + CTRL_ATTR_MCAST_GRP_UNSPEC, + CTRL_ATTR_MCAST_GRP_NAME, + CTRL_ATTR_MCAST_GRP_ID, + __CTRL_ATTR_MCAST_GRP_MAX, +}; + +#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1) + +#endif /* __LINUX_GENERIC_NETLINK_H */ diff --git a/libnetwork/libnl3/include/linux/if.h b/libnetwork/libnl3/include/linux/if.h new file mode 100644 index 0000000..32f910f --- /dev/null +++ b/libnetwork/libnl3/include/linux/if.h @@ -0,0 +1,140 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Global definitions for the INET interface module. + * + * Version: @(#)if.h 1.0.2 04/18/93 + * + * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1982-1988 + * Ross Biro + * Fred N. van Kempen, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _LINUX_IF_H +#define _LINUX_IF_H + +#define IFNAMSIZ 16 +#define IFALIASZ 256 + +/* Standard interface flags (netdevice->flags). */ +#define IFF_UP 0x1 /* interface is up */ +#define IFF_BROADCAST 0x2 /* broadcast address valid */ +#define IFF_DEBUG 0x4 /* turn on debugging */ +#define IFF_LOOPBACK 0x8 /* is a loopback net */ +#define IFF_POINTOPOINT 0x10 /* interface is has p-p link */ +#define IFF_NOTRAILERS 0x20 /* avoid use of trailers */ +#define IFF_RUNNING 0x40 /* interface RFC2863 OPER_UP */ +#define IFF_NOARP 0x80 /* no ARP protocol */ +#define IFF_PROMISC 0x100 /* receive all packets */ +#define IFF_ALLMULTI 0x200 /* receive all multicast packets*/ + +#define IFF_MASTER 0x400 /* master of a load balancer */ +#define IFF_SLAVE 0x800 /* slave of a load balancer */ + +#define IFF_MULTICAST 0x1000 /* Supports multicast */ + +#define IFF_PORTSEL 0x2000 /* can set media type */ +#define IFF_AUTOMEDIA 0x4000 /* auto media select active */ +#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses*/ + +#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ +#define IFF_DORMANT 0x20000 /* driver signals dormant */ + +#define IFF_ECHO 0x40000 /* echo sent packets */ + +#define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\ + IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT) + +/* Private (from user) interface flags (netdevice->priv_flags). */ +#define IFF_802_1Q_VLAN 0x1 /* 802.1Q VLAN device. */ +#define IFF_EBRIDGE 0x2 /* Ethernet bridging device. */ +#define IFF_SLAVE_INACTIVE 0x4 /* bonding slave not the curr. active */ +#define IFF_MASTER_8023AD 0x8 /* bonding master, 802.3ad. */ +#define IFF_MASTER_ALB 0x10 /* bonding master, balance-alb. */ +#define IFF_BONDING 0x20 /* bonding master or slave */ +#define IFF_SLAVE_NEEDARP 0x40 /* need ARPs for validation */ +#define IFF_ISATAP 0x80 /* ISATAP interface (RFC4214) */ +#define IFF_MASTER_ARPMON 0x100 /* bonding master, ARP mon in use */ +#define IFF_WAN_HDLC 0x200 /* WAN HDLC device */ +#define IFF_XMIT_DST_RELEASE 0x400 /* dev_hard_start_xmit() is allowed to + * release skb->dst + */ +#define IFF_DONT_BRIDGE 0x800 /* disallow bridging this ether dev */ +#define IFF_IN_NETPOLL 0x1000 /* whether we are processing netpoll */ +#define IFF_DISABLE_NETPOLL 0x2000 /* disable netpoll at run-time */ +#define IFF_MACVLAN_PORT 0x4000 /* device used as macvlan port */ +#define IFF_BRIDGE_PORT 0x8000 /* device used as bridge port */ +#define IFF_OVS_DATAPATH 0x10000 /* device used as Open vSwitch + * datapath port */ + +#define IF_GET_IFACE 0x0001 /* for querying only */ +#define IF_GET_PROTO 0x0002 + +/* For definitions see hdlc.h */ +#define IF_IFACE_V35 0x1000 /* V.35 serial interface */ +#define IF_IFACE_V24 0x1001 /* V.24 serial interface */ +#define IF_IFACE_X21 0x1002 /* X.21 serial interface */ +#define IF_IFACE_T1 0x1003 /* T1 telco serial interface */ +#define IF_IFACE_E1 0x1004 /* E1 telco serial interface */ +#define IF_IFACE_SYNC_SERIAL 0x1005 /* can't be set by software */ +#define IF_IFACE_X21D 0x1006 /* X.21 Dual Clocking (FarSite) */ + +/* For definitions see hdlc.h */ +#define IF_PROTO_HDLC 0x2000 /* raw HDLC protocol */ +#define IF_PROTO_PPP 0x2001 /* PPP protocol */ +#define IF_PROTO_CISCO 0x2002 /* Cisco HDLC protocol */ +#define IF_PROTO_FR 0x2003 /* Frame Relay protocol */ +#define IF_PROTO_FR_ADD_PVC 0x2004 /* Create FR PVC */ +#define IF_PROTO_FR_DEL_PVC 0x2005 /* Delete FR PVC */ +#define IF_PROTO_X25 0x2006 /* X.25 */ +#define IF_PROTO_HDLC_ETH 0x2007 /* raw HDLC, Ethernet emulation */ +#define IF_PROTO_FR_ADD_ETH_PVC 0x2008 /* Create FR Ethernet-bridged PVC */ +#define IF_PROTO_FR_DEL_ETH_PVC 0x2009 /* Delete FR Ethernet-bridged PVC */ +#define IF_PROTO_FR_PVC 0x200A /* for reading PVC status */ +#define IF_PROTO_FR_ETH_PVC 0x200B +#define IF_PROTO_RAW 0x200C /* RAW Socket */ + +/* RFC 2863 operational status */ +enum { + IF_OPER_UNKNOWN, + IF_OPER_NOTPRESENT, + IF_OPER_DOWN, + IF_OPER_LOWERLAYERDOWN, + IF_OPER_TESTING, + IF_OPER_DORMANT, + IF_OPER_UP, +}; + +/* link modes */ +enum { + IF_LINK_MODE_DEFAULT, + IF_LINK_MODE_DORMANT, /* limit upward transition to dormant */ +}; + +/* + * Device mapping structure. I'd just gone off and designed a + * beautiful scheme using only loadable modules with arguments + * for driver options and along come the PCMCIA people 8) + * + * Ah well. The get() side of this is good for WDSETUP, and it'll + * be handy for debugging things. The set side is fine for now and + * being very small might be worth keeping for clean configuration. + */ + +struct ifmap { + unsigned long mem_start; + unsigned long mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; + /* 3 bytes spare */ +}; + +#endif /* _LINUX_IF_H */ diff --git a/libnetwork/libnl3/include/linux/if_addr.h b/libnetwork/libnl3/include/linux/if_addr.h new file mode 100644 index 0000000..c355522 --- /dev/null +++ b/libnetwork/libnl3/include/linux/if_addr.h @@ -0,0 +1,55 @@ +#ifndef __LINUX_IF_ADDR_H +#define __LINUX_IF_ADDR_H + +#include +#include + +struct ifaddrmsg { + __u8 ifa_family; + __u8 ifa_prefixlen; /* The prefix length */ + __u8 ifa_flags; /* Flags */ + __u8 ifa_scope; /* Address scope */ + __u32 ifa_index; /* Link index */ +}; + +/* + * Important comment: + * IFA_ADDRESS is prefix address, rather than local interface address. + * It makes no difference for normally configured broadcast interfaces, + * but for point-to-point IFA_ADDRESS is DESTINATION address, + * local address is supplied in IFA_LOCAL attribute. + */ +enum { + IFA_UNSPEC, + IFA_ADDRESS, + IFA_LOCAL, + IFA_LABEL, + IFA_BROADCAST, + IFA_ANYCAST, + IFA_CACHEINFO, + IFA_MULTICAST, + __IFA_MAX, +}; + +#define IFA_MAX (__IFA_MAX - 1) + +/* ifa_flags */ +#define IFA_F_SECONDARY 0x01 +#define IFA_F_TEMPORARY IFA_F_SECONDARY + +#define IFA_F_NODAD 0x02 +#define IFA_F_OPTIMISTIC 0x04 +#define IFA_F_DADFAILED 0x08 +#define IFA_F_HOMEADDRESS 0x10 +#define IFA_F_DEPRECATED 0x20 +#define IFA_F_TENTATIVE 0x40 +#define IFA_F_PERMANENT 0x80 + +struct ifa_cacheinfo { + __u32 ifa_prefered; + __u32 ifa_valid; + __u32 cstamp; /* created timestamp, hundredths of seconds */ + __u32 tstamp; /* updated timestamp, hundredths of seconds */ +}; + +#endif diff --git a/libnetwork/libnl3/include/linux/if_arp.h b/libnetwork/libnl3/include/linux/if_arp.h new file mode 100644 index 0000000..e04cd2c --- /dev/null +++ b/libnetwork/libnl3/include/linux/if_arp.h @@ -0,0 +1,156 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Global definitions for the ARP (RFC 826) protocol. + * + * Version: @(#)if_arp.h 1.0.1 04/16/93 + * + * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988 + * Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source. + * Ross Biro + * Fred N. van Kempen, + * Florian La Roche, + * Jonathan Layes + * Arnaldo Carvalho de Melo ARPHRD_HWX25 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _LINUX_IF_ARP_H +#define _LINUX_IF_ARP_H + +#include + +/* ARP protocol HARDWARE identifiers. */ +#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */ +#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */ +#define ARPHRD_EETHER 2 /* Experimental Ethernet */ +#define ARPHRD_AX25 3 /* AX.25 Level 2 */ +#define ARPHRD_PRONET 4 /* PROnet token ring */ +#define ARPHRD_CHAOS 5 /* Chaosnet */ +#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */ +#define ARPHRD_ARCNET 7 /* ARCnet */ +#define ARPHRD_APPLETLK 8 /* APPLEtalk */ +#define ARPHRD_DLCI 15 /* Frame Relay DLCI */ +#define ARPHRD_ATM 19 /* ATM */ +#define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */ +#define ARPHRD_IEEE1394 24 /* IEEE 1394 IPv4 - RFC 2734 */ +#define ARPHRD_EUI64 27 /* EUI-64 */ +#define ARPHRD_INFINIBAND 32 /* InfiniBand */ + +/* Dummy types for non ARP hardware */ +#define ARPHRD_SLIP 256 +#define ARPHRD_CSLIP 257 +#define ARPHRD_SLIP6 258 +#define ARPHRD_CSLIP6 259 +#define ARPHRD_RSRVD 260 /* Notional KISS type */ +#define ARPHRD_ADAPT 264 +#define ARPHRD_ROSE 270 +#define ARPHRD_X25 271 /* CCITT X.25 */ +#define ARPHRD_HWX25 272 /* Boards with X.25 in firmware */ +#define ARPHRD_CAN 280 /* Controller Area Network */ +#define ARPHRD_PPP 512 +#define ARPHRD_CISCO 513 /* Cisco HDLC */ +#define ARPHRD_HDLC ARPHRD_CISCO +#define ARPHRD_LAPB 516 /* LAPB */ +#define ARPHRD_DDCMP 517 /* Digital's DDCMP protocol */ +#define ARPHRD_RAWHDLC 518 /* Raw HDLC */ + +#define ARPHRD_TUNNEL 768 /* IPIP tunnel */ +#define ARPHRD_TUNNEL6 769 /* IP6IP6 tunnel */ +#define ARPHRD_FRAD 770 /* Frame Relay Access Device */ +#define ARPHRD_SKIP 771 /* SKIP vif */ +#define ARPHRD_LOOPBACK 772 /* Loopback device */ +#define ARPHRD_LOCALTLK 773 /* Localtalk device */ +#define ARPHRD_FDDI 774 /* Fiber Distributed Data Interface */ +#define ARPHRD_BIF 775 /* AP1000 BIF */ +#define ARPHRD_SIT 776 /* sit0 device - IPv6-in-IPv4 */ +#define ARPHRD_IPDDP 777 /* IP over DDP tunneller */ +#define ARPHRD_IPGRE 778 /* GRE over IP */ +#define ARPHRD_PIMREG 779 /* PIMSM register interface */ +#define ARPHRD_HIPPI 780 /* High Performance Parallel Interface */ +#define ARPHRD_ASH 781 /* Nexus 64Mbps Ash */ +#define ARPHRD_ECONET 782 /* Acorn Econet */ +#define ARPHRD_IRDA 783 /* Linux-IrDA */ +/* ARP works differently on different FC media .. so */ +#define ARPHRD_FCPP 784 /* Point to point fibrechannel */ +#define ARPHRD_FCAL 785 /* Fibrechannel arbitrated loop */ +#define ARPHRD_FCPL 786 /* Fibrechannel public loop */ +#define ARPHRD_FCFABRIC 787 /* Fibrechannel fabric */ + /* 787->799 reserved for fibrechannel media types */ +#define ARPHRD_IEEE802_TR 800 /* Magic type ident for TR */ +#define ARPHRD_IEEE80211 801 /* IEEE 802.11 */ +#define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */ +#define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */ +#define ARPHRD_IEEE802154 804 + +#define ARPHRD_PHONET 820 /* PhoNet media type */ +#define ARPHRD_PHONET_PIPE 821 /* PhoNet pipe header */ +#define ARPHRD_CAIF 822 /* CAIF media type */ + +#define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */ +#define ARPHRD_NONE 0xFFFE /* zero header length */ + +/* ARP protocol opcodes. */ +#define ARPOP_REQUEST 1 /* ARP request */ +#define ARPOP_REPLY 2 /* ARP reply */ +#define ARPOP_RREQUEST 3 /* RARP request */ +#define ARPOP_RREPLY 4 /* RARP reply */ +#define ARPOP_InREQUEST 8 /* InARP request */ +#define ARPOP_InREPLY 9 /* InARP reply */ +#define ARPOP_NAK 10 /* (ATM)ARP NAK */ + + +/* ARP ioctl request. */ +struct arpreq { + struct sockaddr arp_pa; /* protocol address */ + struct sockaddr arp_ha; /* hardware address */ + int arp_flags; /* flags */ + struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ + char arp_dev[16]; +}; + +struct arpreq_old { + struct sockaddr arp_pa; /* protocol address */ + struct sockaddr arp_ha; /* hardware address */ + int arp_flags; /* flags */ + struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ +}; + +/* ARP Flag values. */ +#define ATF_COM 0x02 /* completed entry (ha valid) */ +#define ATF_PERM 0x04 /* permanent entry */ +#define ATF_PUBL 0x08 /* publish entry */ +#define ATF_USETRAILERS 0x10 /* has requested trailers */ +#define ATF_NETMASK 0x20 /* want to use a netmask (only + for proxy entries) */ +#define ATF_DONTPUB 0x40 /* don't answer this addresses */ + +/* + * This structure defines an ethernet arp header. + */ + +struct arphdr { + __be16 ar_hrd; /* format of hardware address */ + __be16 ar_pro; /* format of protocol address */ + unsigned char ar_hln; /* length of hardware address */ + unsigned char ar_pln; /* length of protocol address */ + __be16 ar_op; /* ARP opcode (command) */ + +#if 0 + /* + * Ethernet looks like this : This bit is variable sized however... + */ + unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ + unsigned char ar_sip[4]; /* sender IP address */ + unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ + unsigned char ar_tip[4]; /* target IP address */ +#endif + +}; + +#endif /* _LINUX_IF_ARP_H */ diff --git a/libnetwork/libnl3/include/linux/if_ether.h b/libnetwork/libnl3/include/linux/if_ether.h new file mode 100644 index 0000000..a6af32d --- /dev/null +++ b/libnetwork/libnl3/include/linux/if_ether.h @@ -0,0 +1,125 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Global definitions for the Ethernet IEEE 802.3 interface. + * + * Version: @(#)if_ether.h 1.0.1a 02/08/94 + * + * Author: Fred N. van Kempen, + * Donald Becker, + * Alan Cox, + * Steve Whitehouse, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _LINUX_IF_ETHER_H +#define _LINUX_IF_ETHER_H + +#include + +/* + * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble + * and FCS/CRC (frame check sequence). + */ + +#define ETH_ALEN 6 /* Octets in one ethernet addr */ +#define ETH_HLEN 14 /* Total octets in header. */ +#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ +#define ETH_DATA_LEN 1500 /* Max. octets in payload */ +#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ +#define ETH_FCS_LEN 4 /* Octets in the FCS */ + +/* + * These are the defined Ethernet Protocol ID's. + */ + +#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */ +#define ETH_P_PUP 0x0200 /* Xerox PUP packet */ +#define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */ +#define ETH_P_IP 0x0800 /* Internet Protocol packet */ +#define ETH_P_X25 0x0805 /* CCITT X.25 */ +#define ETH_P_ARP 0x0806 /* Address Resolution packet */ +#define ETH_P_BPQ 0x08FF /* G8BPQ AX.25 Ethernet Packet [ NOT AN OFFICIALLY REGISTERED ID ] */ +#define ETH_P_IEEEPUP 0x0a00 /* Xerox IEEE802.3 PUP packet */ +#define ETH_P_IEEEPUPAT 0x0a01 /* Xerox IEEE802.3 PUP Addr Trans packet */ +#define ETH_P_DEC 0x6000 /* DEC Assigned proto */ +#define ETH_P_DNA_DL 0x6001 /* DEC DNA Dump/Load */ +#define ETH_P_DNA_RC 0x6002 /* DEC DNA Remote Console */ +#define ETH_P_DNA_RT 0x6003 /* DEC DNA Routing */ +#define ETH_P_LAT 0x6004 /* DEC LAT */ +#define ETH_P_DIAG 0x6005 /* DEC Diagnostics */ +#define ETH_P_CUST 0x6006 /* DEC Customer use */ +#define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */ +#define ETH_P_TEB 0x6558 /* Trans Ether Bridging */ +#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ +#define ETH_P_ATALK 0x809B /* Appletalk DDP */ +#define ETH_P_AARP 0x80F3 /* Appletalk AARP */ +#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */ +#define ETH_P_IPX 0x8137 /* IPX over DIX */ +#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ +#define ETH_P_PAUSE 0x8808 /* IEEE Pause frames. See 802.3 31B */ +#define ETH_P_SLOW 0x8809 /* Slow Protocol. See 802.3ad 43B */ +#define ETH_P_WCCP 0x883E /* Web-cache coordination protocol + * defined in draft-wilson-wrec-wccp-v2-00.txt */ +#define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */ +#define ETH_P_PPP_SES 0x8864 /* PPPoE session messages */ +#define ETH_P_MPLS_UC 0x8847 /* MPLS Unicast traffic */ +#define ETH_P_MPLS_MC 0x8848 /* MPLS Multicast traffic */ +#define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */ +#define ETH_P_LINK_CTL 0x886c /* HPNA, wlan link local tunnel */ +#define ETH_P_ATMFATE 0x8884 /* Frame-based ATM Transport + * over Ethernet + */ +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#define ETH_P_AOE 0x88A2 /* ATA over Ethernet */ +#define ETH_P_TIPC 0x88CA /* TIPC */ +#define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */ +#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */ +#define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */ +#define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */ + +/* + * Non DIX types. Won't clash for 1500 types. + */ + +#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */ +#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ +#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ +#define ETH_P_802_2 0x0004 /* 802.2 frames */ +#define ETH_P_SNAP 0x0005 /* Internal only */ +#define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */ +#define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/ +#define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */ +#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */ +#define ETH_P_CAN 0x000C /* Controller Area Network */ +#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/ +#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */ +#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz at cafe.net) */ +#define ETH_P_CONTROL 0x0016 /* Card specific control frames */ +#define ETH_P_IRDA 0x0017 /* Linux-IrDA */ +#define ETH_P_ECONET 0x0018 /* Acorn Econet */ +#define ETH_P_HDLC 0x0019 /* HDLC frames */ +#define ETH_P_ARCNET 0x001A /* 1A for ArcNet :-) */ +#define ETH_P_DSA 0x001B /* Distributed Switch Arch. */ +#define ETH_P_TRAILER 0x001C /* Trailer switch tagging */ +#define ETH_P_PHONET 0x00F5 /* Nokia Phonet frames */ +#define ETH_P_IEEE802154 0x00F6 /* IEEE802.15.4 frame */ +#define ETH_P_CAIF 0x00F7 /* ST-Ericsson CAIF protocol */ + +/* + * This is an Ethernet frame header. + */ + +struct ethhdr { + unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ + unsigned char h_source[ETH_ALEN]; /* source ether addr */ + __be16 h_proto; /* packet type ID field */ +} __attribute__((packed)); + +#endif /* _LINUX_IF_ETHER_H */ diff --git a/libnetwork/libnl3/include/linux/if_link.h b/libnetwork/libnl3/include/linux/if_link.h new file mode 100644 index 0000000..8a27d5a --- /dev/null +++ b/libnetwork/libnl3/include/linux/if_link.h @@ -0,0 +1,377 @@ +#ifndef _LINUX_IF_LINK_H +#define _LINUX_IF_LINK_H + +#include +#include + +/* This struct should be in sync with struct rtnl_link_stats64 */ +struct rtnl_link_stats { + __u32 rx_packets; /* total packets received */ + __u32 tx_packets; /* total packets transmitted */ + __u32 rx_bytes; /* total bytes received */ + __u32 tx_bytes; /* total bytes transmitted */ + __u32 rx_errors; /* bad packets received */ + __u32 tx_errors; /* packet transmit problems */ + __u32 rx_dropped; /* no space in linux buffers */ + __u32 tx_dropped; /* no space available in linux */ + __u32 multicast; /* multicast packets received */ + __u32 collisions; + + /* detailed rx_errors: */ + __u32 rx_length_errors; + __u32 rx_over_errors; /* receiver ring buff overflow */ + __u32 rx_crc_errors; /* recved pkt with crc error */ + __u32 rx_frame_errors; /* recv'd frame alignment error */ + __u32 rx_fifo_errors; /* recv'r fifo overrun */ + __u32 rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + __u32 tx_aborted_errors; + __u32 tx_carrier_errors; + __u32 tx_fifo_errors; + __u32 tx_heartbeat_errors; + __u32 tx_window_errors; + + /* for cslip etc */ + __u32 rx_compressed; + __u32 tx_compressed; +}; + +/* The main device statistics structure */ +struct rtnl_link_stats64 { + __u64 rx_packets; /* total packets received */ + __u64 tx_packets; /* total packets transmitted */ + __u64 rx_bytes; /* total bytes received */ + __u64 tx_bytes; /* total bytes transmitted */ + __u64 rx_errors; /* bad packets received */ + __u64 tx_errors; /* packet transmit problems */ + __u64 rx_dropped; /* no space in linux buffers */ + __u64 tx_dropped; /* no space available in linux */ + __u64 multicast; /* multicast packets received */ + __u64 collisions; + + /* detailed rx_errors: */ + __u64 rx_length_errors; + __u64 rx_over_errors; /* receiver ring buff overflow */ + __u64 rx_crc_errors; /* recved pkt with crc error */ + __u64 rx_frame_errors; /* recv'd frame alignment error */ + __u64 rx_fifo_errors; /* recv'r fifo overrun */ + __u64 rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + __u64 tx_aborted_errors; + __u64 tx_carrier_errors; + __u64 tx_fifo_errors; + __u64 tx_heartbeat_errors; + __u64 tx_window_errors; + + /* for cslip etc */ + __u64 rx_compressed; + __u64 tx_compressed; +}; + +/* The struct should be in sync with struct ifmap */ +struct rtnl_link_ifmap { + __u64 mem_start; + __u64 mem_end; + __u64 base_addr; + __u16 irq; + __u8 dma; + __u8 port; +}; + +/* + * IFLA_AF_SPEC + * Contains nested attributes for address family specific attributes. + * Each address family may create a attribute with the address family + * number as type and create its own attribute structure in it. + * + * Example: + * [IFLA_AF_SPEC] = { + * [AF_INET] = { + * [IFLA_INET_CONF] = ..., + * }, + * [AF_INET6] = { + * [IFLA_INET6_FLAGS] = ..., + * [IFLA_INET6_CONF] = ..., + * } + * } + */ + +enum { + IFLA_UNSPEC, + IFLA_ADDRESS, + IFLA_BROADCAST, + IFLA_IFNAME, + IFLA_MTU, + IFLA_LINK, + IFLA_QDISC, + IFLA_STATS, + IFLA_COST, +#define IFLA_COST IFLA_COST + IFLA_PRIORITY, +#define IFLA_PRIORITY IFLA_PRIORITY + IFLA_MASTER, +#define IFLA_MASTER IFLA_MASTER + IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */ +#define IFLA_WIRELESS IFLA_WIRELESS + IFLA_PROTINFO, /* Protocol specific information for a link */ +#define IFLA_PROTINFO IFLA_PROTINFO + IFLA_TXQLEN, +#define IFLA_TXQLEN IFLA_TXQLEN + IFLA_MAP, +#define IFLA_MAP IFLA_MAP + IFLA_WEIGHT, +#define IFLA_WEIGHT IFLA_WEIGHT + IFLA_OPERSTATE, + IFLA_LINKMODE, + IFLA_LINKINFO, +#define IFLA_LINKINFO IFLA_LINKINFO + IFLA_NET_NS_PID, + IFLA_IFALIAS, + IFLA_NUM_VF, /* Number of VFs if device is SR-IOV PF */ + IFLA_VFINFO_LIST, + IFLA_STATS64, + IFLA_VF_PORTS, + IFLA_PORT_SELF, + IFLA_AF_SPEC, + IFLA_GROUP, /* Group the device belongs to */ + IFLA_NET_NS_FD, + __IFLA_MAX +}; + + +#define IFLA_MAX (__IFLA_MAX - 1) + +enum { + IFLA_INET_UNSPEC, + IFLA_INET_CONF, + __IFLA_INET_MAX, +}; + +#define IFLA_INET_MAX (__IFLA_INET_MAX - 1) + +/* ifi_flags. + + IFF_* flags. + + The only change is: + IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are + more not changeable by user. They describe link media + characteristics and set by device driver. + + Comments: + - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid + - If neither of these three flags are set; + the interface is NBMA. + + - IFF_MULTICAST does not mean anything special: + multicasts can be used on all not-NBMA links. + IFF_MULTICAST means that this media uses special encapsulation + for multicast frames. Apparently, all IFF_POINTOPOINT and + IFF_BROADCAST devices are able to use multicasts too. + */ + +/* IFLA_LINK. + For usual devices it is equal ifi_index. + If it is a "virtual interface" (f.e. tunnel), ifi_link + can point to real physical interface (f.e. for bandwidth calculations), + or maybe 0, what means, that real media is unknown (usual + for IPIP tunnels, when route to endpoint is allowed to change) + */ + +/* Subtype attributes for IFLA_PROTINFO */ +enum { + IFLA_INET6_UNSPEC, + IFLA_INET6_FLAGS, /* link flags */ + IFLA_INET6_CONF, /* sysctl parameters */ + IFLA_INET6_STATS, /* statistics */ + IFLA_INET6_MCAST, /* MC things. What of them? */ + IFLA_INET6_CACHEINFO, /* time values and max reasm size */ + IFLA_INET6_ICMP6STATS, /* statistics (icmpv6) */ + __IFLA_INET6_MAX +}; + +#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1) + +struct ifla_cacheinfo { + __u32 max_reasm_len; + __u32 tstamp; /* ipv6InterfaceTable updated timestamp */ + __u32 reachable_time; + __u32 retrans_time; +}; + +enum { + IFLA_INFO_UNSPEC, + IFLA_INFO_KIND, + IFLA_INFO_DATA, + IFLA_INFO_XSTATS, + __IFLA_INFO_MAX, +}; + +#define IFLA_INFO_MAX (__IFLA_INFO_MAX - 1) + +/* VLAN section */ + +enum { + IFLA_VLAN_UNSPEC, + IFLA_VLAN_ID, + IFLA_VLAN_FLAGS, + IFLA_VLAN_EGRESS_QOS, + IFLA_VLAN_INGRESS_QOS, + __IFLA_VLAN_MAX, +}; + +#define IFLA_VLAN_MAX (__IFLA_VLAN_MAX - 1) + +struct ifla_vlan_flags { + __u32 flags; + __u32 mask; +}; + +enum { + IFLA_VLAN_QOS_UNSPEC, + IFLA_VLAN_QOS_MAPPING, + __IFLA_VLAN_QOS_MAX +}; + +#define IFLA_VLAN_QOS_MAX (__IFLA_VLAN_QOS_MAX - 1) + +struct ifla_vlan_qos_mapping { + __u32 from; + __u32 to; +}; + +/* MACVLAN section */ +enum { + IFLA_MACVLAN_UNSPEC, + IFLA_MACVLAN_MODE, + __IFLA_MACVLAN_MAX, +}; + +#define IFLA_MACVLAN_MAX (__IFLA_MACVLAN_MAX - 1) + +enum macvlan_mode { + MACVLAN_MODE_PRIVATE = 1, /* don't talk to other macvlans */ + MACVLAN_MODE_VEPA = 2, /* talk to other ports through ext bridge */ + MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */ + MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */ +}; + +/* SR-IOV virtual function management section */ + +enum { + IFLA_VF_INFO_UNSPEC, + IFLA_VF_INFO, + __IFLA_VF_INFO_MAX, +}; + +#define IFLA_VF_INFO_MAX (__IFLA_VF_INFO_MAX - 1) + +enum { + IFLA_VF_UNSPEC, + IFLA_VF_MAC, /* Hardware queue specific attributes */ + IFLA_VF_VLAN, + IFLA_VF_TX_RATE, /* TX Bandwidth Allocation */ + __IFLA_VF_MAX, +}; + +#define IFLA_VF_MAX (__IFLA_VF_MAX - 1) + +struct ifla_vf_mac { + __u32 vf; + __u8 mac[32]; /* MAX_ADDR_LEN */ +}; + +struct ifla_vf_vlan { + __u32 vf; + __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */ + __u32 qos; +}; + +struct ifla_vf_tx_rate { + __u32 vf; + __u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */ +}; + +struct ifla_vf_info { + __u32 vf; + __u8 mac[32]; + __u32 vlan; + __u32 qos; + __u32 tx_rate; +}; + +/* VF ports management section + * + * Nested layout of set/get msg is: + * + * [IFLA_NUM_VF] + * [IFLA_VF_PORTS] + * [IFLA_VF_PORT] + * [IFLA_PORT_*], ... + * [IFLA_VF_PORT] + * [IFLA_PORT_*], ... + * ... + * [IFLA_PORT_SELF] + * [IFLA_PORT_*], ... + */ + +enum { + IFLA_VF_PORT_UNSPEC, + IFLA_VF_PORT, /* nest */ + __IFLA_VF_PORT_MAX, +}; + +#define IFLA_VF_PORT_MAX (__IFLA_VF_PORT_MAX - 1) + +enum { + IFLA_PORT_UNSPEC, + IFLA_PORT_VF, /* __u32 */ + IFLA_PORT_PROFILE, /* string */ + IFLA_PORT_VSI_TYPE, /* 802.1Qbg (pre-)standard VDP */ + IFLA_PORT_INSTANCE_UUID, /* binary UUID */ + IFLA_PORT_HOST_UUID, /* binary UUID */ + IFLA_PORT_REQUEST, /* __u8 */ + IFLA_PORT_RESPONSE, /* __u16, output only */ + __IFLA_PORT_MAX, +}; + +#define IFLA_PORT_MAX (__IFLA_PORT_MAX - 1) + +#define PORT_PROFILE_MAX 40 +#define PORT_UUID_MAX 16 +#define PORT_SELF_VF -1 + +enum { + PORT_REQUEST_PREASSOCIATE = 0, + PORT_REQUEST_PREASSOCIATE_RR, + PORT_REQUEST_ASSOCIATE, + PORT_REQUEST_DISASSOCIATE, +}; + +enum { + PORT_VDP_RESPONSE_SUCCESS = 0, + PORT_VDP_RESPONSE_INVALID_FORMAT, + PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES, + PORT_VDP_RESPONSE_UNUSED_VTID, + PORT_VDP_RESPONSE_VTID_VIOLATION, + PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION, + PORT_VDP_RESPONSE_OUT_OF_SYNC, + /* 0x08-0xFF reserved for future VDP use */ + PORT_PROFILE_RESPONSE_SUCCESS = 0x100, + PORT_PROFILE_RESPONSE_INPROGRESS, + PORT_PROFILE_RESPONSE_INVALID, + PORT_PROFILE_RESPONSE_BADSTATE, + PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES, + PORT_PROFILE_RESPONSE_ERROR, +}; + +struct ifla_port_vsi { + __u8 vsi_mgr_id; + __u8 vsi_type_id[3]; + __u8 vsi_type_version; + __u8 pad[3]; +}; + +#endif /* _LINUX_IF_LINK_H */ diff --git a/libnetwork/libnl3/include/linux/if_vlan.h b/libnetwork/libnl3/include/linux/if_vlan.h new file mode 100644 index 0000000..67affd1 --- /dev/null +++ b/libnetwork/libnl3/include/linux/if_vlan.h @@ -0,0 +1,62 @@ +/* + * VLAN An implementation of 802.1Q VLAN tagging. + * + * Authors: Ben Greear + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#ifndef _LINUX_IF_VLAN_H_ +#define _LINUX_IF_VLAN_H_ + +/* VLAN IOCTLs are found in sockios.h */ + +/* Passed in vlan_ioctl_args structure to determine behaviour. */ +enum vlan_ioctl_cmds { + ADD_VLAN_CMD, + DEL_VLAN_CMD, + SET_VLAN_INGRESS_PRIORITY_CMD, + SET_VLAN_EGRESS_PRIORITY_CMD, + GET_VLAN_INGRESS_PRIORITY_CMD, + GET_VLAN_EGRESS_PRIORITY_CMD, + SET_VLAN_NAME_TYPE_CMD, + SET_VLAN_FLAG_CMD, + GET_VLAN_REALDEV_NAME_CMD, /* If this works, you know it's a VLAN device, btw */ + GET_VLAN_VID_CMD /* Get the VID of this VLAN (specified by name) */ +}; + +enum vlan_flags { + VLAN_FLAG_REORDER_HDR = 0x1, + VLAN_FLAG_GVRP = 0x2, + VLAN_FLAG_LOOSE_BINDING = 0x4, +}; + +enum vlan_name_types { + VLAN_NAME_TYPE_PLUS_VID, /* Name will look like: vlan0005 */ + VLAN_NAME_TYPE_RAW_PLUS_VID, /* name will look like: eth1.0005 */ + VLAN_NAME_TYPE_PLUS_VID_NO_PAD, /* Name will look like: vlan5 */ + VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, /* Name will look like: eth0.5 */ + VLAN_NAME_TYPE_HIGHEST +}; + +struct vlan_ioctl_args { + int cmd; /* Should be one of the vlan_ioctl_cmds enum above. */ + char device1[24]; + + union { + char device2[24]; + int VID; + unsigned int skb_priority; + unsigned int name_type; + unsigned int bind_type; + unsigned int flag; /* Matches vlan_dev_info flags */ + } u; + + short vlan_qos; +}; + +#endif /* !(_LINUX_IF_VLAN_H_) */ diff --git a/libnetwork/libnl3/include/linux/inetdevice.h b/libnetwork/libnl3/include/linux/inetdevice.h new file mode 100644 index 0000000..fd4d2df --- /dev/null +++ b/libnetwork/libnl3/include/linux/inetdevice.h @@ -0,0 +1,36 @@ +#ifndef _LINUX_INETDEVICE_H +#define _LINUX_INETDEVICE_H + +enum +{ + IPV4_DEVCONF_FORWARDING=1, + IPV4_DEVCONF_MC_FORWARDING, + IPV4_DEVCONF_PROXY_ARP, + IPV4_DEVCONF_ACCEPT_REDIRECTS, + IPV4_DEVCONF_SECURE_REDIRECTS, + IPV4_DEVCONF_SEND_REDIRECTS, + IPV4_DEVCONF_SHARED_MEDIA, + IPV4_DEVCONF_RP_FILTER, + IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE, + IPV4_DEVCONF_BOOTP_RELAY, + IPV4_DEVCONF_LOG_MARTIANS, + IPV4_DEVCONF_TAG, + IPV4_DEVCONF_ARPFILTER, + IPV4_DEVCONF_MEDIUM_ID, + IPV4_DEVCONF_NOXFRM, + IPV4_DEVCONF_NOPOLICY, + IPV4_DEVCONF_FORCE_IGMP_VERSION, + IPV4_DEVCONF_ARP_ANNOUNCE, + IPV4_DEVCONF_ARP_IGNORE, + IPV4_DEVCONF_PROMOTE_SECONDARIES, + IPV4_DEVCONF_ARP_ACCEPT, + IPV4_DEVCONF_ARP_NOTIFY, + IPV4_DEVCONF_ACCEPT_LOCAL, + IPV4_DEVCONF_SRC_VMARK, + IPV4_DEVCONF_PROXY_ARP_PVLAN, + __IPV4_DEVCONF_MAX +}; + +#define IPV4_DEVCONF_MAX (__IPV4_DEVCONF_MAX - 1) + +#endif /* _LINUX_INETDEVICE_H */ diff --git a/libnetwork/libnl3/include/linux/ip_mp_alg.h b/libnetwork/libnl3/include/linux/ip_mp_alg.h new file mode 100644 index 0000000..e234e20 --- /dev/null +++ b/libnetwork/libnl3/include/linux/ip_mp_alg.h @@ -0,0 +1,22 @@ +/* ip_mp_alg.h: IPV4 multipath algorithm support, user-visible values. + * + * Copyright (C) 2004, 2005 Einar Lueck + * Copyright (C) 2005 David S. Miller + */ + +#ifndef _LINUX_IP_MP_ALG_H +#define _LINUX_IP_MP_ALG_H + +enum ip_mp_alg { + IP_MP_ALG_NONE, + IP_MP_ALG_RR, + IP_MP_ALG_DRR, + IP_MP_ALG_RANDOM, + IP_MP_ALG_WRANDOM, + __IP_MP_ALG_MAX +}; + +#define IP_MP_ALG_MAX (__IP_MP_ALG_MAX - 1) + +#endif /* _LINUX_IP_MP_ALG_H */ + diff --git a/libnetwork/libnl3/include/linux/ipv6.h b/libnetwork/libnl3/include/linux/ipv6.h new file mode 100644 index 0000000..f16349d --- /dev/null +++ b/libnetwork/libnl3/include/linux/ipv6.h @@ -0,0 +1,146 @@ +#ifndef _IPV6_H +#define _IPV6_H + +#include + +/* The latest drafts declared increase in minimal mtu up to 1280. */ + +#define IPV6_MIN_MTU 1280 + +/* + * Advanced API + * source interface/address selection, source routing, etc... + * *under construction* + */ + + +#define IPV6_SRCRT_STRICT 0x01 /* Deprecated; will be removed */ +#define IPV6_SRCRT_TYPE_0 0 /* Deprecated; will be removed */ +#define IPV6_SRCRT_TYPE_2 2 /* IPv6 type 2 Routing Header */ + +/* + * routing header + */ +struct ipv6_rt_hdr { + __u8 nexthdr; + __u8 hdrlen; + __u8 type; + __u8 segments_left; + + /* + * type specific data + * variable length field + */ +}; + + +struct ipv6_opt_hdr { + __u8 nexthdr; + __u8 hdrlen; + /* + * TLV encoded option data follows. + */ +} __attribute__((packed)); /* required for some archs */ + +#define ipv6_destopt_hdr ipv6_opt_hdr +#define ipv6_hopopt_hdr ipv6_opt_hdr + + +/* + * routing header type 0 (used in cmsghdr struct) + */ + +struct rt0_hdr { + struct ipv6_rt_hdr rt_hdr; + __u32 reserved; + struct in6_addr addr[0]; + +#define rt0_type rt_hdr.type +}; + +/* + * routing header type 2 + */ + +struct rt2_hdr { + struct ipv6_rt_hdr rt_hdr; + __u32 reserved; + struct in6_addr addr; + +#define rt2_type rt_hdr.type +}; + +/* + * home address option in destination options header + */ + +struct ipv6_destopt_hao { + __u8 type; + __u8 length; + struct in6_addr addr; +} __attribute__((packed)); + +/* + * IPv6 fixed header + * + * BEWARE, it is incorrect. The first 4 bits of flow_lbl + * are glued to priority now, forming "class". + */ + +struct ipv6hdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 priority:4, + version:4; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u8 version:4, + priority:4; +#else +#error "Please fix " +#endif + __u8 flow_lbl[3]; + + __be16 payload_len; + __u8 nexthdr; + __u8 hop_limit; + + struct in6_addr saddr; + struct in6_addr daddr; +}; + + +/* index values for the variables in ipv6_devconf */ +enum { + DEVCONF_FORWARDING = 0, + DEVCONF_HOPLIMIT, + DEVCONF_MTU6, + DEVCONF_ACCEPT_RA, + DEVCONF_ACCEPT_REDIRECTS, + DEVCONF_AUTOCONF, + DEVCONF_DAD_TRANSMITS, + DEVCONF_RTR_SOLICITS, + DEVCONF_RTR_SOLICIT_INTERVAL, + DEVCONF_RTR_SOLICIT_DELAY, + DEVCONF_USE_TEMPADDR, + DEVCONF_TEMP_VALID_LFT, + DEVCONF_TEMP_PREFERED_LFT, + DEVCONF_REGEN_MAX_RETRY, + DEVCONF_MAX_DESYNC_FACTOR, + DEVCONF_MAX_ADDRESSES, + DEVCONF_FORCE_MLD_VERSION, + DEVCONF_ACCEPT_RA_DEFRTR, + DEVCONF_ACCEPT_RA_PINFO, + DEVCONF_ACCEPT_RA_RTR_PREF, + DEVCONF_RTR_PROBE_INTERVAL, + DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN, + DEVCONF_PROXY_NDP, + DEVCONF_OPTIMISTIC_DAD, + DEVCONF_ACCEPT_SOURCE_ROUTE, + DEVCONF_MC_FORWARDING, + DEVCONF_DISABLE_IPV6, + DEVCONF_ACCEPT_DAD, + DEVCONF_FORCE_TLLAO, + DEVCONF_MAX +}; + + +#endif /* _IPV6_H */ diff --git a/libnetwork/libnl3/include/linux/neighbour.h b/libnetwork/libnl3/include/linux/neighbour.h new file mode 100644 index 0000000..a7003b7 --- /dev/null +++ b/libnetwork/libnl3/include/linux/neighbour.h @@ -0,0 +1,155 @@ +#ifndef __LINUX_NEIGHBOUR_H +#define __LINUX_NEIGHBOUR_H + +#include +#include + +struct ndmsg { + __u8 ndm_family; + __u8 ndm_pad1; + __u16 ndm_pad2; + __s32 ndm_ifindex; + __u16 ndm_state; + __u8 ndm_flags; + __u8 ndm_type; +}; + +enum { + NDA_UNSPEC, + NDA_DST, + NDA_LLADDR, + NDA_CACHEINFO, + NDA_PROBES, + __NDA_MAX +}; + +#define NDA_MAX (__NDA_MAX - 1) + +/* + * Neighbor Cache Entry Flags + */ + +#define NTF_USE 0x01 +#define NTF_PROXY 0x08 /* == ATF_PUBL */ +#define NTF_ROUTER 0x80 + +/* + * Neighbor Cache Entry States. + */ + +#define NUD_INCOMPLETE 0x01 +#define NUD_REACHABLE 0x02 +#define NUD_STALE 0x04 +#define NUD_DELAY 0x08 +#define NUD_PROBE 0x10 +#define NUD_FAILED 0x20 + +/* Dummy states */ +#define NUD_NOARP 0x40 +#define NUD_PERMANENT 0x80 +#define NUD_NONE 0x00 + +/* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change + and make no address resolution or NUD. + NUD_PERMANENT is also cannot be deleted by garbage collectors. + */ + +struct nda_cacheinfo { + __u32 ndm_confirmed; + __u32 ndm_used; + __u32 ndm_updated; + __u32 ndm_refcnt; +}; + +/***************************************************************** + * Neighbour tables specific messages. + * + * To retrieve the neighbour tables send RTM_GETNEIGHTBL with the + * NLM_F_DUMP flag set. Every neighbour table configuration is + * spread over multiple messages to avoid running into message + * size limits on systems with many interfaces. The first message + * in the sequence transports all not device specific data such as + * statistics, configuration, and the default parameter set. + * This message is followed by 0..n messages carrying device + * specific parameter sets. + * Although the ordering should be sufficient, NDTA_NAME can be + * used to identify sequences. The initial message can be identified + * by checking for NDTA_CONFIG. The device specific messages do + * not contain this TLV but have NDTPA_IFINDEX set to the + * corresponding interface index. + * + * To change neighbour table attributes, send RTM_SETNEIGHTBL + * with NDTA_NAME set. Changeable attribute include NDTA_THRESH[1-3], + * NDTA_GC_INTERVAL, and all TLVs in NDTA_PARMS unless marked + * otherwise. Device specific parameter sets can be changed by + * setting NDTPA_IFINDEX to the interface index of the corresponding + * device. + ****/ + +struct ndt_stats { + __u64 ndts_allocs; + __u64 ndts_destroys; + __u64 ndts_hash_grows; + __u64 ndts_res_failed; + __u64 ndts_lookups; + __u64 ndts_hits; + __u64 ndts_rcv_probes_mcast; + __u64 ndts_rcv_probes_ucast; + __u64 ndts_periodic_gc_runs; + __u64 ndts_forced_gc_runs; +}; + +enum { + NDTPA_UNSPEC, + NDTPA_IFINDEX, /* u32, unchangeable */ + NDTPA_REFCNT, /* u32, read-only */ + NDTPA_REACHABLE_TIME, /* u64, read-only, msecs */ + NDTPA_BASE_REACHABLE_TIME, /* u64, msecs */ + NDTPA_RETRANS_TIME, /* u64, msecs */ + NDTPA_GC_STALETIME, /* u64, msecs */ + NDTPA_DELAY_PROBE_TIME, /* u64, msecs */ + NDTPA_QUEUE_LEN, /* u32 */ + NDTPA_APP_PROBES, /* u32 */ + NDTPA_UCAST_PROBES, /* u32 */ + NDTPA_MCAST_PROBES, /* u32 */ + NDTPA_ANYCAST_DELAY, /* u64, msecs */ + NDTPA_PROXY_DELAY, /* u64, msecs */ + NDTPA_PROXY_QLEN, /* u32 */ + NDTPA_LOCKTIME, /* u64, msecs */ + __NDTPA_MAX +}; +#define NDTPA_MAX (__NDTPA_MAX - 1) + +struct ndtmsg { + __u8 ndtm_family; + __u8 ndtm_pad1; + __u16 ndtm_pad2; +}; + +struct ndt_config { + __u16 ndtc_key_len; + __u16 ndtc_entry_size; + __u32 ndtc_entries; + __u32 ndtc_last_flush; /* delta to now in msecs */ + __u32 ndtc_last_rand; /* delta to now in msecs */ + __u32 ndtc_hash_rnd; + __u32 ndtc_hash_mask; + __u32 ndtc_hash_chain_gc; + __u32 ndtc_proxy_qlen; +}; + +enum { + NDTA_UNSPEC, + NDTA_NAME, /* char *, unchangeable */ + NDTA_THRESH1, /* u32 */ + NDTA_THRESH2, /* u32 */ + NDTA_THRESH3, /* u32 */ + NDTA_CONFIG, /* struct ndt_config, read-only */ + NDTA_PARMS, /* nested TLV NDTPA_* */ + NDTA_STATS, /* struct ndt_stats, read-only */ + NDTA_GC_INTERVAL, /* u64, msecs */ + __NDTA_MAX +}; +#define NDTA_MAX (__NDTA_MAX - 1) + +#endif diff --git a/libnetwork/libnl3/include/linux/netfilter.h b/libnetwork/libnl3/include/linux/netfilter.h new file mode 100644 index 0000000..7999885 --- /dev/null +++ b/libnetwork/libnl3/include/linux/netfilter.h @@ -0,0 +1,57 @@ +#ifndef __LINUX_NETFILTER_H +#define __LINUX_NETFILTER_H + +#include + +/* Responses from hook functions. */ +#define NF_DROP 0 +#define NF_ACCEPT 1 +#define NF_STOLEN 2 +#define NF_QUEUE 3 +#define NF_REPEAT 4 +#define NF_STOP 5 +#define NF_MAX_VERDICT NF_STOP + +/* we overload the higher bits for encoding auxiliary data such as the queue + * number. Not nice, but better than additional function arguments. */ +#define NF_VERDICT_MASK 0x0000ffff +#define NF_VERDICT_BITS 16 + +#define NF_VERDICT_QMASK 0xffff0000 +#define NF_VERDICT_QBITS 16 + +#define NF_QUEUE_NR(x) ((((x) << NF_VERDICT_BITS) & NF_VERDICT_QMASK) | NF_QUEUE) + +/* Generic cache responses from hook functions. + <= 0x2000 is used for protocol-flags. */ +#define NFC_UNKNOWN 0x4000 +#define NFC_ALTERED 0x8000 + +enum nf_inet_hooks { + NF_INET_PRE_ROUTING, + NF_INET_LOCAL_IN, + NF_INET_FORWARD, + NF_INET_LOCAL_OUT, + NF_INET_POST_ROUTING, + NF_INET_NUMHOOKS +}; + +enum { + NFPROTO_UNSPEC = 0, + NFPROTO_IPV4 = 2, + NFPROTO_ARP = 3, + NFPROTO_BRIDGE = 7, + NFPROTO_IPV6 = 10, + NFPROTO_DECNET = 12, + NFPROTO_NUMPROTO, +}; + +union nf_inet_addr { + __u32 all[4]; + __be32 ip; + __be32 ip6[4]; + struct in_addr in; + struct in6_addr in6; +}; + +#endif /*__LINUX_NETFILTER_H*/ diff --git a/libnetwork/libnl3/include/linux/netfilter/nfnetlink.h b/libnetwork/libnl3/include/linux/netfilter/nfnetlink.h new file mode 100644 index 0000000..1e59984 --- /dev/null +++ b/libnetwork/libnl3/include/linux/netfilter/nfnetlink.h @@ -0,0 +1,60 @@ +#ifndef _NFNETLINK_H +#define _NFNETLINK_H +#include + +#ifndef __KERNEL__ +/* nfnetlink groups: Up to 32 maximum - backwards compatibility for userspace */ +#define NF_NETLINK_CONNTRACK_NEW 0x00000001 +#define NF_NETLINK_CONNTRACK_UPDATE 0x00000002 +#define NF_NETLINK_CONNTRACK_DESTROY 0x00000004 +#define NF_NETLINK_CONNTRACK_EXP_NEW 0x00000008 +#define NF_NETLINK_CONNTRACK_EXP_UPDATE 0x00000010 +#define NF_NETLINK_CONNTRACK_EXP_DESTROY 0x00000020 +#endif + +enum nfnetlink_groups { + NFNLGRP_NONE, +#define NFNLGRP_NONE NFNLGRP_NONE + NFNLGRP_CONNTRACK_NEW, +#define NFNLGRP_CONNTRACK_NEW NFNLGRP_CONNTRACK_NEW + NFNLGRP_CONNTRACK_UPDATE, +#define NFNLGRP_CONNTRACK_UPDATE NFNLGRP_CONNTRACK_UPDATE + NFNLGRP_CONNTRACK_DESTROY, +#define NFNLGRP_CONNTRACK_DESTROY NFNLGRP_CONNTRACK_DESTROY + NFNLGRP_CONNTRACK_EXP_NEW, +#define NFNLGRP_CONNTRACK_EXP_NEW NFNLGRP_CONNTRACK_EXP_NEW + NFNLGRP_CONNTRACK_EXP_UPDATE, +#define NFNLGRP_CONNTRACK_EXP_UPDATE NFNLGRP_CONNTRACK_EXP_UPDATE + NFNLGRP_CONNTRACK_EXP_DESTROY, +#define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY + __NFNLGRP_MAX, +}; +#define NFNLGRP_MAX (__NFNLGRP_MAX - 1) + +/* General form of address family dependent message. + */ +struct nfgenmsg { + u_int8_t nfgen_family; /* AF_xxx */ + u_int8_t version; /* nfnetlink version */ + __be16 res_id; /* resource id */ +}; + +#define NFNETLINK_V0 0 + +/* netfilter netlink message types are split in two pieces: + * 8 bit subsystem, 8bit operation. + */ + +#define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8) +#define NFNL_MSG_TYPE(x) (x & 0x00ff) + +/* No enum here, otherwise __stringify() trick of MODULE_ALIAS_NFNL_SUBSYS() + * won't work anymore */ +#define NFNL_SUBSYS_NONE 0 +#define NFNL_SUBSYS_CTNETLINK 1 +#define NFNL_SUBSYS_CTNETLINK_EXP 2 +#define NFNL_SUBSYS_QUEUE 3 +#define NFNL_SUBSYS_ULOG 4 +#define NFNL_SUBSYS_COUNT 5 + +#endif /* _NFNETLINK_H */ diff --git a/libnetwork/libnl3/include/linux/netfilter/nfnetlink_conntrack.h b/libnetwork/libnl3/include/linux/netfilter/nfnetlink_conntrack.h new file mode 100644 index 0000000..d7c3503 --- /dev/null +++ b/libnetwork/libnl3/include/linux/netfilter/nfnetlink_conntrack.h @@ -0,0 +1,140 @@ +#ifndef _IPCONNTRACK_NETLINK_H +#define _IPCONNTRACK_NETLINK_H +#include + +enum cntl_msg_types { + IPCTNL_MSG_CT_NEW, + IPCTNL_MSG_CT_GET, + IPCTNL_MSG_CT_DELETE, + IPCTNL_MSG_CT_GET_CTRZERO, + + IPCTNL_MSG_MAX +}; + +enum ctnl_exp_msg_types { + IPCTNL_MSG_EXP_NEW, + IPCTNL_MSG_EXP_GET, + IPCTNL_MSG_EXP_DELETE, + + IPCTNL_MSG_EXP_MAX +}; + + +enum ctattr_type { + CTA_UNSPEC, + CTA_TUPLE_ORIG, + CTA_TUPLE_REPLY, + CTA_STATUS, + CTA_PROTOINFO, + CTA_HELP, + CTA_NAT_SRC, +#define CTA_NAT CTA_NAT_SRC /* backwards compatibility */ + CTA_TIMEOUT, + CTA_MARK, + CTA_COUNTERS_ORIG, + CTA_COUNTERS_REPLY, + CTA_USE, + CTA_ID, + CTA_NAT_DST, + __CTA_MAX +}; +#define CTA_MAX (__CTA_MAX - 1) + +enum ctattr_tuple { + CTA_TUPLE_UNSPEC, + CTA_TUPLE_IP, + CTA_TUPLE_PROTO, + __CTA_TUPLE_MAX +}; +#define CTA_TUPLE_MAX (__CTA_TUPLE_MAX - 1) + +enum ctattr_ip { + CTA_IP_UNSPEC, + CTA_IP_V4_SRC, + CTA_IP_V4_DST, + CTA_IP_V6_SRC, + CTA_IP_V6_DST, + __CTA_IP_MAX +}; +#define CTA_IP_MAX (__CTA_IP_MAX - 1) + +enum ctattr_l4proto { + CTA_PROTO_UNSPEC, + CTA_PROTO_NUM, + CTA_PROTO_SRC_PORT, + CTA_PROTO_DST_PORT, + CTA_PROTO_ICMP_ID, + CTA_PROTO_ICMP_TYPE, + CTA_PROTO_ICMP_CODE, + CTA_PROTO_ICMPV6_ID, + CTA_PROTO_ICMPV6_TYPE, + CTA_PROTO_ICMPV6_CODE, + __CTA_PROTO_MAX +}; +#define CTA_PROTO_MAX (__CTA_PROTO_MAX - 1) + +enum ctattr_protoinfo { + CTA_PROTOINFO_UNSPEC, + CTA_PROTOINFO_TCP, + __CTA_PROTOINFO_MAX +}; +#define CTA_PROTOINFO_MAX (__CTA_PROTOINFO_MAX - 1) + +enum ctattr_protoinfo_tcp { + CTA_PROTOINFO_TCP_UNSPEC, + CTA_PROTOINFO_TCP_STATE, + CTA_PROTOINFO_TCP_WSCALE_ORIGINAL, + CTA_PROTOINFO_TCP_WSCALE_REPLY, + CTA_PROTOINFO_TCP_FLAGS_ORIGINAL, + CTA_PROTOINFO_TCP_FLAGS_REPLY, + __CTA_PROTOINFO_TCP_MAX +}; +#define CTA_PROTOINFO_TCP_MAX (__CTA_PROTOINFO_TCP_MAX - 1) + +enum ctattr_counters { + CTA_COUNTERS_UNSPEC, + CTA_COUNTERS_PACKETS, /* old 64bit counters */ + CTA_COUNTERS_BYTES, /* old 64bit counters */ + CTA_COUNTERS32_PACKETS, + CTA_COUNTERS32_BYTES, + __CTA_COUNTERS_MAX +}; +#define CTA_COUNTERS_MAX (__CTA_COUNTERS_MAX - 1) + +enum ctattr_nat { + CTA_NAT_UNSPEC, + CTA_NAT_MINIP, + CTA_NAT_MAXIP, + CTA_NAT_PROTO, + __CTA_NAT_MAX +}; +#define CTA_NAT_MAX (__CTA_NAT_MAX - 1) + +enum ctattr_protonat { + CTA_PROTONAT_UNSPEC, + CTA_PROTONAT_PORT_MIN, + CTA_PROTONAT_PORT_MAX, + __CTA_PROTONAT_MAX +}; +#define CTA_PROTONAT_MAX (__CTA_PROTONAT_MAX - 1) + +enum ctattr_expect { + CTA_EXPECT_UNSPEC, + CTA_EXPECT_MASTER, + CTA_EXPECT_TUPLE, + CTA_EXPECT_MASK, + CTA_EXPECT_TIMEOUT, + CTA_EXPECT_ID, + CTA_EXPECT_HELP_NAME, + __CTA_EXPECT_MAX +}; +#define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1) + +enum ctattr_help { + CTA_HELP_UNSPEC, + CTA_HELP_NAME, + __CTA_HELP_MAX +}; +#define CTA_HELP_MAX (__CTA_HELP_MAX - 1) + +#endif /* _IPCONNTRACK_NETLINK_H */ diff --git a/libnetwork/libnl3/include/linux/netfilter/nfnetlink_log.h b/libnetwork/libnl3/include/linux/netfilter/nfnetlink_log.h new file mode 100644 index 0000000..38fafc1 --- /dev/null +++ b/libnetwork/libnl3/include/linux/netfilter/nfnetlink_log.h @@ -0,0 +1,97 @@ +#ifndef _NFNETLINK_LOG_H +#define _NFNETLINK_LOG_H + +/* This file describes the netlink messages (i.e. 'protocol packets'), + * and not any kind of function definitions. It is shared between kernel and + * userspace. Don't put kernel specific stuff in here */ + +#ifndef aligned_be64 +#define aligned_be64 u_int64_t __attribute__((aligned(8))) +#endif + +#include +#include + +enum nfulnl_msg_types { + NFULNL_MSG_PACKET, /* packet from kernel to userspace */ + NFULNL_MSG_CONFIG, /* connect to a particular queue */ + + NFULNL_MSG_MAX +}; + +struct nfulnl_msg_packet_hdr { + __be16 hw_protocol; /* hw protocol (network order) */ + u_int8_t hook; /* netfilter hook */ + u_int8_t _pad; +}; + +struct nfulnl_msg_packet_hw { + __be16 hw_addrlen; + u_int16_t _pad; + u_int8_t hw_addr[8]; +}; + +struct nfulnl_msg_packet_timestamp { + aligned_be64 sec; + aligned_be64 usec; +}; + +enum nfulnl_attr_type { + NFULA_UNSPEC, + NFULA_PACKET_HDR, + NFULA_MARK, /* u_int32_t nfmark */ + NFULA_TIMESTAMP, /* nfulnl_msg_packet_timestamp */ + NFULA_IFINDEX_INDEV, /* u_int32_t ifindex */ + NFULA_IFINDEX_OUTDEV, /* u_int32_t ifindex */ + NFULA_IFINDEX_PHYSINDEV, /* u_int32_t ifindex */ + NFULA_IFINDEX_PHYSOUTDEV, /* u_int32_t ifindex */ + NFULA_HWADDR, /* nfulnl_msg_packet_hw */ + NFULA_PAYLOAD, /* opaque data payload */ + NFULA_PREFIX, /* string prefix */ + NFULA_UID, /* user id of socket */ + NFULA_SEQ, /* instance-local sequence number */ + NFULA_SEQ_GLOBAL, /* global sequence number */ + NFULA_GID, /* group id of socket */ + + __NFULA_MAX +}; +#define NFULA_MAX (__NFULA_MAX - 1) + +enum nfulnl_msg_config_cmds { + NFULNL_CFG_CMD_NONE, + NFULNL_CFG_CMD_BIND, + NFULNL_CFG_CMD_UNBIND, + NFULNL_CFG_CMD_PF_BIND, + NFULNL_CFG_CMD_PF_UNBIND, +}; + +struct nfulnl_msg_config_cmd { + u_int8_t command; /* nfulnl_msg_config_cmds */ +} __attribute__ ((packed)); + +struct nfulnl_msg_config_mode { + __be32 copy_range; + u_int8_t copy_mode; + u_int8_t _pad; +} __attribute__ ((packed)); + +enum nfulnl_attr_config { + NFULA_CFG_UNSPEC, + NFULA_CFG_CMD, /* nfulnl_msg_config_cmd */ + NFULA_CFG_MODE, /* nfulnl_msg_config_mode */ + NFULA_CFG_NLBUFSIZ, /* u_int32_t buffer size */ + NFULA_CFG_TIMEOUT, /* u_int32_t in 1/100 s */ + NFULA_CFG_QTHRESH, /* u_int32_t */ + NFULA_CFG_FLAGS, /* u_int16_t */ + __NFULA_CFG_MAX +}; +#define NFULA_CFG_MAX (__NFULA_CFG_MAX -1) + +#define NFULNL_COPY_NONE 0x00 +#define NFULNL_COPY_META 0x01 +#define NFULNL_COPY_PACKET 0x02 + +#define NFULNL_CFG_F_SEQ 0x0001 +#define NFULNL_CFG_F_SEQ_GLOBAL 0x0002 + +#endif /* _NFNETLINK_LOG_H */ diff --git a/libnetwork/libnl3/include/linux/netfilter/nfnetlink_queue.h b/libnetwork/libnl3/include/linux/netfilter/nfnetlink_queue.h new file mode 100644 index 0000000..bf7cfb6 --- /dev/null +++ b/libnetwork/libnl3/include/linux/netfilter/nfnetlink_queue.h @@ -0,0 +1,94 @@ +#ifndef _NFNETLINK_QUEUE_H +#define _NFNETLINK_QUEUE_H + +#include +#include + +#ifndef aligned_be64 +#define aligned_be64 u_int64_t __attribute__((aligned(8))) +#endif + +enum nfqnl_msg_types { + NFQNL_MSG_PACKET, /* packet from kernel to userspace */ + NFQNL_MSG_VERDICT, /* verdict from userspace to kernel */ + NFQNL_MSG_CONFIG, /* connect to a particular queue */ + + NFQNL_MSG_MAX +}; + +struct nfqnl_msg_packet_hdr { + __be32 packet_id; /* unique ID of packet in queue */ + __be16 hw_protocol; /* hw protocol (network order) */ + u_int8_t hook; /* netfilter hook */ +} __attribute__ ((packed)); + +struct nfqnl_msg_packet_hw { + __be16 hw_addrlen; + u_int16_t _pad; + u_int8_t hw_addr[8]; +}; + +struct nfqnl_msg_packet_timestamp { + aligned_be64 sec; + aligned_be64 usec; +}; + +enum nfqnl_attr_type { + NFQA_UNSPEC, + NFQA_PACKET_HDR, + NFQA_VERDICT_HDR, /* nfqnl_msg_verdict_hrd */ + NFQA_MARK, /* u_int32_t nfmark */ + NFQA_TIMESTAMP, /* nfqnl_msg_packet_timestamp */ + NFQA_IFINDEX_INDEV, /* u_int32_t ifindex */ + NFQA_IFINDEX_OUTDEV, /* u_int32_t ifindex */ + NFQA_IFINDEX_PHYSINDEV, /* u_int32_t ifindex */ + NFQA_IFINDEX_PHYSOUTDEV, /* u_int32_t ifindex */ + NFQA_HWADDR, /* nfqnl_msg_packet_hw */ + NFQA_PAYLOAD, /* opaque data payload */ + + __NFQA_MAX +}; +#define NFQA_MAX (__NFQA_MAX - 1) + +struct nfqnl_msg_verdict_hdr { + __be32 verdict; + __be32 id; +}; + + +enum nfqnl_msg_config_cmds { + NFQNL_CFG_CMD_NONE, + NFQNL_CFG_CMD_BIND, + NFQNL_CFG_CMD_UNBIND, + NFQNL_CFG_CMD_PF_BIND, + NFQNL_CFG_CMD_PF_UNBIND, +}; + +struct nfqnl_msg_config_cmd { + u_int8_t command; /* nfqnl_msg_config_cmds */ + u_int8_t _pad; + __be16 pf; /* AF_xxx for PF_[UN]BIND */ +}; + +enum nfqnl_config_mode { + NFQNL_COPY_NONE, + NFQNL_COPY_META, + NFQNL_COPY_PACKET, +}; + +struct nfqnl_msg_config_params { + __be32 copy_range; + u_int8_t copy_mode; /* enum nfqnl_config_mode */ +} __attribute__ ((packed)); + + +enum nfqnl_attr_config { + NFQA_CFG_UNSPEC, + NFQA_CFG_CMD, /* nfqnl_msg_config_cmd */ + NFQA_CFG_PARAMS, /* nfqnl_msg_config_params */ + NFQA_CFG_QUEUE_MAXLEN, /* u_int32_t */ + __NFQA_CFG_MAX +}; +#define NFQA_CFG_MAX (__NFQA_CFG_MAX-1) + +#endif /* _NFNETLINK_QUEUE_H */ diff --git a/libnetwork/libnl3/include/linux/netlink.h b/libnetwork/libnl3/include/linux/netlink.h new file mode 100644 index 0000000..3925254 --- /dev/null +++ b/libnetwork/libnl3/include/linux/netlink.h @@ -0,0 +1,149 @@ +#ifndef __LINUX_NETLINK_H +#define __LINUX_NETLINK_H + +#include /* for sa_family_t */ +#include + +#define NETLINK_ROUTE 0 /* Routing/device hook */ +#define NETLINK_UNUSED 1 /* Unused number */ +#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ +#define NETLINK_FIREWALL 3 /* Firewalling hook */ +#define NETLINK_INET_DIAG 4 /* INET socket monitoring */ +#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */ +#define NETLINK_XFRM 6 /* ipsec */ +#define NETLINK_SELINUX 7 /* SELinux event notifications */ +#define NETLINK_ISCSI 8 /* Open-iSCSI */ +#define NETLINK_AUDIT 9 /* auditing */ +#define NETLINK_FIB_LOOKUP 10 +#define NETLINK_CONNECTOR 11 +#define NETLINK_NETFILTER 12 /* netfilter subsystem */ +#define NETLINK_IP6_FW 13 +#define NETLINK_DNRTMSG 14 /* DECnet routing messages */ +#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */ +#define NETLINK_GENERIC 16 +/* leave room for NETLINK_DM (DM Events) */ +#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */ +#define NETLINK_ECRYPTFS 19 +#define NETLINK_RDMA 20 + +#define MAX_LINKS 32 + +struct sockaddr_nl { + sa_family_t nl_family; /* AF_NETLINK */ + unsigned short nl_pad; /* zero */ + __u32 nl_pid; /* port ID */ + __u32 nl_groups; /* multicast groups mask */ +}; + +struct nlmsghdr { + __u32 nlmsg_len; /* Length of message including header */ + __u16 nlmsg_type; /* Message content */ + __u16 nlmsg_flags; /* Additional flags */ + __u32 nlmsg_seq; /* Sequence number */ + __u32 nlmsg_pid; /* Sending process port ID */ +}; + +/* Flags values */ + +#define NLM_F_REQUEST 1 /* It is request message. */ +#define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */ +#define NLM_F_ACK 4 /* Reply with ack, with zero or error code */ +#define NLM_F_ECHO 8 /* Echo this request */ +#define NLM_F_DUMP_INTR 16 /* Dump was inconsistent due to sequence change */ + +/* Modifiers to GET request */ +#define NLM_F_ROOT 0x100 /* specify tree root */ +#define NLM_F_MATCH 0x200 /* return all matching */ +#define NLM_F_ATOMIC 0x400 /* atomic GET */ +#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH) + +/* Modifiers to NEW request */ +#define NLM_F_REPLACE 0x100 /* Override existing */ +#define NLM_F_EXCL 0x200 /* Do not touch, if it exists */ +#define NLM_F_CREATE 0x400 /* Create, if it does not exist */ +#define NLM_F_APPEND 0x800 /* Add to end of list */ + +/* + 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL + 4.4BSD CHANGE NLM_F_REPLACE + + True CHANGE NLM_F_CREATE|NLM_F_REPLACE + Append NLM_F_CREATE + Check NLM_F_EXCL + */ + +#define NLMSG_ALIGNTO 4U +#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) ) +#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) +#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN)) +#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len)) +#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0))) +#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ + (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) +#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \ + (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \ + (nlh)->nlmsg_len <= (len)) +#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len))) + +#define NLMSG_NOOP 0x1 /* Nothing. */ +#define NLMSG_ERROR 0x2 /* Error */ +#define NLMSG_DONE 0x3 /* End of a dump */ +#define NLMSG_OVERRUN 0x4 /* Data lost */ + +#define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */ + +struct nlmsgerr { + int error; + struct nlmsghdr msg; +}; + +#define NETLINK_ADD_MEMBERSHIP 1 +#define NETLINK_DROP_MEMBERSHIP 2 +#define NETLINK_PKTINFO 3 +#define NETLINK_BROADCAST_ERROR 4 +#define NETLINK_NO_ENOBUFS 5 + +struct nl_pktinfo { + __u32 group; +}; + +#define NET_MAJOR 36 /* Major 36 is reserved for networking */ + +enum { + NETLINK_UNCONNECTED = 0, + NETLINK_CONNECTED, +}; + +/* + * <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)--> + * +---------------------+- - -+- - - - - - - - - -+- - -+ + * | Header | Pad | Payload | Pad | + * | (struct nlattr) | ing | | ing | + * +---------------------+- - -+- - - - - - - - - -+- - -+ + * <-------------- nlattr->nla_len --------------> + */ + +struct nlattr { + __u16 nla_len; + __u16 nla_type; +}; + +/* + * nla_type (16 bits) + * +---+---+-------------------------------+ + * | N | O | Attribute Type | + * +---+---+-------------------------------+ + * N := Carries nested attributes + * O := Payload stored in network byte order + * + * Note: The N and O flag are mutually exclusive. + */ +#define NLA_F_NESTED (1 << 15) +#define NLA_F_NET_BYTEORDER (1 << 14) +#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER) + +#define NLA_ALIGNTO 4 +#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1)) +#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr))) + +#endif /* __LINUX_NETLINK_H */ diff --git a/libnetwork/libnl3/include/linux/pkt_cls.h b/libnetwork/libnl3/include/linux/pkt_cls.h new file mode 100644 index 0000000..defbde2 --- /dev/null +++ b/libnetwork/libnl3/include/linux/pkt_cls.h @@ -0,0 +1,467 @@ +#ifndef __LINUX_PKT_CLS_H +#define __LINUX_PKT_CLS_H + +#include +#include + +/* I think i could have done better macros ; for now this is stolen from + * some arch/mips code - jhs +*/ +#define _TC_MAKE32(x) ((x)) + +#define _TC_MAKEMASK1(n) (_TC_MAKE32(1) << _TC_MAKE32(n)) +#define _TC_MAKEMASK(v,n) (_TC_MAKE32((_TC_MAKE32(1)<<(v))-1) << _TC_MAKE32(n)) +#define _TC_MAKEVALUE(v,n) (_TC_MAKE32(v) << _TC_MAKE32(n)) +#define _TC_GETVALUE(v,n,m) ((_TC_MAKE32(v) & _TC_MAKE32(m)) >> _TC_MAKE32(n)) + +/* verdict bit breakdown + * +bit 0: when set -> this packet has been munged already + +bit 1: when set -> It is ok to munge this packet + +bit 2,3,4,5: Reclassify counter - sort of reverse TTL - if exceeded +assume loop + +bit 6,7: Where this packet was last seen +0: Above the transmit example at the socket level +1: on the Ingress +2: on the Egress + +bit 8: when set --> Request not to classify on ingress. + +bits 9,10,11: redirect counter - redirect TTL. Loop avoidance + + * + * */ + +#define TC_MUNGED _TC_MAKEMASK1(0) +#define SET_TC_MUNGED(v) ( TC_MUNGED | (v & ~TC_MUNGED)) +#define CLR_TC_MUNGED(v) ( v & ~TC_MUNGED) + +#define TC_OK2MUNGE _TC_MAKEMASK1(1) +#define SET_TC_OK2MUNGE(v) ( TC_OK2MUNGE | (v & ~TC_OK2MUNGE)) +#define CLR_TC_OK2MUNGE(v) ( v & ~TC_OK2MUNGE) + +#define S_TC_VERD _TC_MAKE32(2) +#define M_TC_VERD _TC_MAKEMASK(4,S_TC_VERD) +#define G_TC_VERD(x) _TC_GETVALUE(x,S_TC_VERD,M_TC_VERD) +#define V_TC_VERD(x) _TC_MAKEVALUE(x,S_TC_VERD) +#define SET_TC_VERD(v,n) ((V_TC_VERD(n)) | (v & ~M_TC_VERD)) + +#define S_TC_FROM _TC_MAKE32(6) +#define M_TC_FROM _TC_MAKEMASK(2,S_TC_FROM) +#define G_TC_FROM(x) _TC_GETVALUE(x,S_TC_FROM,M_TC_FROM) +#define V_TC_FROM(x) _TC_MAKEVALUE(x,S_TC_FROM) +#define SET_TC_FROM(v,n) ((V_TC_FROM(n)) | (v & ~M_TC_FROM)) +#define AT_STACK 0x0 +#define AT_INGRESS 0x1 +#define AT_EGRESS 0x2 + +#define TC_NCLS _TC_MAKEMASK1(8) +#define SET_TC_NCLS(v) ( TC_NCLS | (v & ~TC_NCLS)) +#define CLR_TC_NCLS(v) ( v & ~TC_NCLS) + +#define S_TC_RTTL _TC_MAKE32(9) +#define M_TC_RTTL _TC_MAKEMASK(3,S_TC_RTTL) +#define G_TC_RTTL(x) _TC_GETVALUE(x,S_TC_RTTL,M_TC_RTTL) +#define V_TC_RTTL(x) _TC_MAKEVALUE(x,S_TC_RTTL) +#define SET_TC_RTTL(v,n) ((V_TC_RTTL(n)) | (v & ~M_TC_RTTL)) + +#define S_TC_AT _TC_MAKE32(12) +#define M_TC_AT _TC_MAKEMASK(2,S_TC_AT) +#define G_TC_AT(x) _TC_GETVALUE(x,S_TC_AT,M_TC_AT) +#define V_TC_AT(x) _TC_MAKEVALUE(x,S_TC_AT) +#define SET_TC_AT(v,n) ((V_TC_AT(n)) | (v & ~M_TC_AT)) + +/* Action attributes */ +enum { + TCA_ACT_UNSPEC, + TCA_ACT_KIND, + TCA_ACT_OPTIONS, + TCA_ACT_INDEX, + TCA_ACT_STATS, + __TCA_ACT_MAX +}; + +#define TCA_ACT_MAX __TCA_ACT_MAX +#define TCA_OLD_COMPAT (TCA_ACT_MAX+1) +#define TCA_ACT_MAX_PRIO 32 +#define TCA_ACT_BIND 1 +#define TCA_ACT_NOBIND 0 +#define TCA_ACT_UNBIND 1 +#define TCA_ACT_NOUNBIND 0 +#define TCA_ACT_REPLACE 1 +#define TCA_ACT_NOREPLACE 0 +#define MAX_REC_LOOP 4 +#define MAX_RED_LOOP 4 + +#define TC_ACT_UNSPEC (-1) +#define TC_ACT_OK 0 +#define TC_ACT_RECLASSIFY 1 +#define TC_ACT_SHOT 2 +#define TC_ACT_PIPE 3 +#define TC_ACT_STOLEN 4 +#define TC_ACT_QUEUED 5 +#define TC_ACT_REPEAT 6 +#define TC_ACT_JUMP 0x10000000 + +/* Action type identifiers*/ +enum { + TCA_ID_UNSPEC=0, + TCA_ID_POLICE=1, + /* other actions go here */ + __TCA_ID_MAX=255 +}; + +#define TCA_ID_MAX __TCA_ID_MAX + +struct tc_police { + __u32 index; + int action; +#define TC_POLICE_UNSPEC TC_ACT_UNSPEC +#define TC_POLICE_OK TC_ACT_OK +#define TC_POLICE_RECLASSIFY TC_ACT_RECLASSIFY +#define TC_POLICE_SHOT TC_ACT_SHOT +#define TC_POLICE_PIPE TC_ACT_PIPE + + __u32 limit; + __u32 burst; + __u32 mtu; + struct tc_ratespec rate; + struct tc_ratespec peakrate; + int refcnt; + int bindcnt; + __u32 capab; +}; + +struct tcf_t { + __u64 install; + __u64 lastuse; + __u64 expires; +}; + +struct tc_cnt { + int refcnt; + int bindcnt; +}; + +#define tc_gen \ + __u32 index; \ + __u32 capab; \ + int action; \ + int refcnt; \ + int bindcnt + +enum { + TCA_POLICE_UNSPEC, + TCA_POLICE_TBF, + TCA_POLICE_RATE, + TCA_POLICE_PEAKRATE, + TCA_POLICE_AVRATE, + TCA_POLICE_RESULT, + __TCA_POLICE_MAX +#define TCA_POLICE_RESULT TCA_POLICE_RESULT +}; + +#define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1) + +/* U32 filters */ + +#define TC_U32_HTID(h) ((h)&0xFFF00000) +#define TC_U32_USERHTID(h) (TC_U32_HTID(h)>>20) +#define TC_U32_HASH(h) (((h)>>12)&0xFF) +#define TC_U32_NODE(h) ((h)&0xFFF) +#define TC_U32_KEY(h) ((h)&0xFFFFF) +#define TC_U32_UNSPEC 0 +#define TC_U32_ROOT (0xFFF00000) + +enum { + TCA_U32_UNSPEC, + TCA_U32_CLASSID, + TCA_U32_HASH, + TCA_U32_LINK, + TCA_U32_DIVISOR, + TCA_U32_SEL, + TCA_U32_POLICE, + TCA_U32_ACT, + TCA_U32_INDEV, + TCA_U32_PCNT, + TCA_U32_MARK, + __TCA_U32_MAX +}; + +#define TCA_U32_MAX (__TCA_U32_MAX - 1) + +struct tc_u32_key { + __be32 mask; + __be32 val; + int off; + int offmask; +}; + +struct tc_u32_sel { + unsigned char flags; + unsigned char offshift; + unsigned char nkeys; + + __be16 offmask; + __u16 off; + short offoff; + + short hoff; + __be32 hmask; + struct tc_u32_key keys[0]; +}; + +struct tc_u32_mark { + __u32 val; + __u32 mask; + __u32 success; +}; + +struct tc_u32_pcnt { + __u64 rcnt; + __u64 rhit; + __u64 kcnts[0]; +}; + +/* Flags */ + +#define TC_U32_TERMINAL 1 +#define TC_U32_OFFSET 2 +#define TC_U32_VAROFFSET 4 +#define TC_U32_EAT 8 + +#define TC_U32_MAXDEPTH 8 + + +/* RSVP filter */ + +enum { + TCA_RSVP_UNSPEC, + TCA_RSVP_CLASSID, + TCA_RSVP_DST, + TCA_RSVP_SRC, + TCA_RSVP_PINFO, + TCA_RSVP_POLICE, + TCA_RSVP_ACT, + __TCA_RSVP_MAX +}; + +#define TCA_RSVP_MAX (__TCA_RSVP_MAX - 1 ) + +struct tc_rsvp_gpi { + __u32 key; + __u32 mask; + int offset; +}; + +struct tc_rsvp_pinfo { + struct tc_rsvp_gpi dpi; + struct tc_rsvp_gpi spi; + __u8 protocol; + __u8 tunnelid; + __u8 tunnelhdr; + __u8 pad; +}; + +/* ROUTE filter */ + +enum { + TCA_ROUTE4_UNSPEC, + TCA_ROUTE4_CLASSID, + TCA_ROUTE4_TO, + TCA_ROUTE4_FROM, + TCA_ROUTE4_IIF, + TCA_ROUTE4_POLICE, + TCA_ROUTE4_ACT, + __TCA_ROUTE4_MAX +}; + +#define TCA_ROUTE4_MAX (__TCA_ROUTE4_MAX - 1) + + +/* FW filter */ + +enum { + TCA_FW_UNSPEC, + TCA_FW_CLASSID, + TCA_FW_POLICE, + TCA_FW_INDEV, /* used by CONFIG_NET_CLS_IND */ + TCA_FW_ACT, /* used by CONFIG_NET_CLS_ACT */ + TCA_FW_MASK, + __TCA_FW_MAX +}; + +#define TCA_FW_MAX (__TCA_FW_MAX - 1) + +/* TC index filter */ + +enum { + TCA_TCINDEX_UNSPEC, + TCA_TCINDEX_HASH, + TCA_TCINDEX_MASK, + TCA_TCINDEX_SHIFT, + TCA_TCINDEX_FALL_THROUGH, + TCA_TCINDEX_CLASSID, + TCA_TCINDEX_POLICE, + TCA_TCINDEX_ACT, + __TCA_TCINDEX_MAX +}; + +#define TCA_TCINDEX_MAX (__TCA_TCINDEX_MAX - 1) + +/* Flow filter */ + +enum { + FLOW_KEY_SRC, + FLOW_KEY_DST, + FLOW_KEY_PROTO, + FLOW_KEY_PROTO_SRC, + FLOW_KEY_PROTO_DST, + FLOW_KEY_IIF, + FLOW_KEY_PRIORITY, + FLOW_KEY_MARK, + FLOW_KEY_NFCT, + FLOW_KEY_NFCT_SRC, + FLOW_KEY_NFCT_DST, + FLOW_KEY_NFCT_PROTO_SRC, + FLOW_KEY_NFCT_PROTO_DST, + FLOW_KEY_RTCLASSID, + FLOW_KEY_SKUID, + FLOW_KEY_SKGID, + FLOW_KEY_VLAN_TAG, + FLOW_KEY_RXHASH, + __FLOW_KEY_MAX, +}; + +#define FLOW_KEY_MAX (__FLOW_KEY_MAX - 1) + +enum { + FLOW_MODE_MAP, + FLOW_MODE_HASH, +}; + +enum { + TCA_FLOW_UNSPEC, + TCA_FLOW_KEYS, + TCA_FLOW_MODE, + TCA_FLOW_BASECLASS, + TCA_FLOW_RSHIFT, + TCA_FLOW_ADDEND, + TCA_FLOW_MASK, + TCA_FLOW_XOR, + TCA_FLOW_DIVISOR, + TCA_FLOW_ACT, + TCA_FLOW_POLICE, + TCA_FLOW_EMATCHES, + TCA_FLOW_PERTURB, + __TCA_FLOW_MAX +}; + +#define TCA_FLOW_MAX (__TCA_FLOW_MAX - 1) + +/* Basic filter */ + +enum { + TCA_BASIC_UNSPEC, + TCA_BASIC_CLASSID, + TCA_BASIC_EMATCHES, + TCA_BASIC_ACT, + TCA_BASIC_POLICE, + __TCA_BASIC_MAX +}; + +#define TCA_BASIC_MAX (__TCA_BASIC_MAX - 1) + + +/* Cgroup classifier */ + +enum { + TCA_CGROUP_UNSPEC, + TCA_CGROUP_ACT, + TCA_CGROUP_POLICE, + TCA_CGROUP_EMATCHES, + __TCA_CGROUP_MAX, +}; + +#define TCA_CGROUP_MAX (__TCA_CGROUP_MAX - 1) + +/* Extended Matches */ + +struct tcf_ematch_tree_hdr { + __u16 nmatches; + __u16 progid; +}; + +enum { + TCA_EMATCH_TREE_UNSPEC, + TCA_EMATCH_TREE_HDR, + TCA_EMATCH_TREE_LIST, + __TCA_EMATCH_TREE_MAX +}; +#define TCA_EMATCH_TREE_MAX (__TCA_EMATCH_TREE_MAX - 1) + +struct tcf_ematch_hdr { + __u16 matchid; + __u16 kind; + __u16 flags; + __u16 pad; /* currently unused */ +}; + +/* 0 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +-----------------------+-+-+---+ + * | Unused |S|I| R | + * +-----------------------+-+-+---+ + * + * R(2) ::= relation to next ematch + * where: 0 0 END (last ematch) + * 0 1 AND + * 1 0 OR + * 1 1 Unused (invalid) + * I(1) ::= invert result + * S(1) ::= simple payload + */ +#define TCF_EM_REL_END 0 +#define TCF_EM_REL_AND (1<<0) +#define TCF_EM_REL_OR (1<<1) +#define TCF_EM_INVERT (1<<2) +#define TCF_EM_SIMPLE (1<<3) + +#define TCF_EM_REL_MASK 3 +#define TCF_EM_REL_VALID(v) (((v) & TCF_EM_REL_MASK) != TCF_EM_REL_MASK) + +enum { + TCF_LAYER_LINK, + TCF_LAYER_NETWORK, + TCF_LAYER_TRANSPORT, + __TCF_LAYER_MAX +}; +#define TCF_LAYER_MAX (__TCF_LAYER_MAX - 1) + +/* Ematch type assignments + * 1..32767 Reserved for ematches inside kernel tree + * 32768..65535 Free to use, not reliable + */ +#define TCF_EM_CONTAINER 0 +#define TCF_EM_CMP 1 +#define TCF_EM_NBYTE 2 +#define TCF_EM_U32 3 +#define TCF_EM_META 4 +#define TCF_EM_TEXT 5 +#define TCF_EM_VLAN 6 +#define TCF_EM_MAX 6 + +enum { + TCF_EM_PROG_TC +}; + +enum { + TCF_EM_OPND_EQ, + TCF_EM_OPND_GT, + TCF_EM_OPND_LT +}; + +#endif diff --git a/libnetwork/libnl3/include/linux/pkt_sched.h b/libnetwork/libnl3/include/linux/pkt_sched.h new file mode 100644 index 0000000..c533670 --- /dev/null +++ b/libnetwork/libnl3/include/linux/pkt_sched.h @@ -0,0 +1,606 @@ +#ifndef __LINUX_PKT_SCHED_H +#define __LINUX_PKT_SCHED_H + +#include + +/* Logical priority bands not depending on specific packet scheduler. + Every scheduler will map them to real traffic classes, if it has + no more precise mechanism to classify packets. + + These numbers have no special meaning, though their coincidence + with obsolete IPv6 values is not occasional :-). New IPv6 drafts + preferred full anarchy inspired by diffserv group. + + Note: TC_PRIO_BESTEFFORT does not mean that it is the most unhappy + class, actually, as rule it will be handled with more care than + filler or even bulk. + */ + +#define TC_PRIO_BESTEFFORT 0 +#define TC_PRIO_FILLER 1 +#define TC_PRIO_BULK 2 +#define TC_PRIO_INTERACTIVE_BULK 4 +#define TC_PRIO_INTERACTIVE 6 +#define TC_PRIO_CONTROL 7 + +#define TC_PRIO_MAX 15 + +/* Generic queue statistics, available for all the elements. + Particular schedulers may have also their private records. + */ + +struct tc_stats { + __u64 bytes; /* NUmber of enqueues bytes */ + __u32 packets; /* Number of enqueued packets */ + __u32 drops; /* Packets dropped because of lack of resources */ + __u32 overlimits; /* Number of throttle events when this + * flow goes out of allocated bandwidth */ + __u32 bps; /* Current flow byte rate */ + __u32 pps; /* Current flow packet rate */ + __u32 qlen; + __u32 backlog; +}; + +struct tc_estimator { + signed char interval; + unsigned char ewma_log; +}; + +/* "Handles" + --------- + + All the traffic control objects have 32bit identifiers, or "handles". + + They can be considered as opaque numbers from user API viewpoint, + but actually they always consist of two fields: major and + minor numbers, which are interpreted by kernel specially, + that may be used by applications, though not recommended. + + F.e. qdisc handles always have minor number equal to zero, + classes (or flows) have major equal to parent qdisc major, and + minor uniquely identifying class inside qdisc. + + Macros to manipulate handles: + */ + +#define TC_H_MAJ_MASK (0xFFFF0000U) +#define TC_H_MIN_MASK (0x0000FFFFU) +#define TC_H_MAJ(h) ((h)&TC_H_MAJ_MASK) +#define TC_H_MIN(h) ((h)&TC_H_MIN_MASK) +#define TC_H_MAKE(maj,min) (((maj)&TC_H_MAJ_MASK)|((min)&TC_H_MIN_MASK)) + +#define TC_H_UNSPEC (0U) +#define TC_H_ROOT (0xFFFFFFFFU) +#define TC_H_INGRESS (0xFFFFFFF1U) + +struct tc_ratespec { + unsigned char cell_log; + unsigned char __reserved; + unsigned short overhead; + short cell_align; + unsigned short mpu; + __u32 rate; +}; + +#define TC_RTAB_SIZE 1024 + +struct tc_sizespec { + unsigned char cell_log; + unsigned char size_log; + short cell_align; + int overhead; + unsigned int linklayer; + unsigned int mpu; + unsigned int mtu; + unsigned int tsize; +}; + +enum { + TCA_STAB_UNSPEC, + TCA_STAB_BASE, + TCA_STAB_DATA, + __TCA_STAB_MAX +}; + +#define TCA_STAB_MAX (__TCA_STAB_MAX - 1) + +/* FIFO section */ + +struct tc_fifo_qopt { + __u32 limit; /* Queue length: bytes for bfifo, packets for pfifo */ +}; + +/* PRIO section */ + +#define TCQ_PRIO_BANDS 16 +#define TCQ_MIN_PRIO_BANDS 2 + +struct tc_prio_qopt { + int bands; /* Number of bands */ + __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */ +}; + +/* MULTIQ section */ + +struct tc_multiq_qopt { + __u16 bands; /* Number of bands */ + __u16 max_bands; /* Maximum number of queues */ +}; + +/* TBF section */ + +struct tc_tbf_qopt { + struct tc_ratespec rate; + struct tc_ratespec peakrate; + __u32 limit; + __u32 buffer; + __u32 mtu; +}; + +enum { + TCA_TBF_UNSPEC, + TCA_TBF_PARMS, + TCA_TBF_RTAB, + TCA_TBF_PTAB, + __TCA_TBF_MAX, +}; + +#define TCA_TBF_MAX (__TCA_TBF_MAX - 1) + + +/* TEQL section */ + +/* TEQL does not require any parameters */ + +/* SFQ section */ + +struct tc_sfq_qopt { + unsigned quantum; /* Bytes per round allocated to flow */ + int perturb_period; /* Period of hash perturbation */ + __u32 limit; /* Maximal packets in queue */ + unsigned divisor; /* Hash divisor */ + unsigned flows; /* Maximal number of flows */ +}; + +struct tc_sfq_xstats { + __s32 allot; +}; + +/* + * NOTE: limit, divisor and flows are hardwired to code at the moment. + * + * limit=flows=128, divisor=1024; + * + * The only reason for this is efficiency, it is possible + * to change these parameters in compile time. + */ + +/* RED section */ + +enum { + TCA_RED_UNSPEC, + TCA_RED_PARMS, + TCA_RED_STAB, + __TCA_RED_MAX, +}; + +#define TCA_RED_MAX (__TCA_RED_MAX - 1) + +struct tc_red_qopt { + __u32 limit; /* HARD maximal queue length (bytes) */ + __u32 qth_min; /* Min average length threshold (bytes) */ + __u32 qth_max; /* Max average length threshold (bytes) */ + unsigned char Wlog; /* log(W) */ + unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ + unsigned char Scell_log; /* cell size for idle damping */ + unsigned char flags; +#define TC_RED_ECN 1 +#define TC_RED_HARDDROP 2 +}; + +struct tc_red_xstats { + __u32 early; /* Early drops */ + __u32 pdrop; /* Drops due to queue limits */ + __u32 other; /* Drops due to drop() calls */ + __u32 marked; /* Marked packets */ +}; + +/* GRED section */ + +#define MAX_DPs 16 + +enum { + TCA_GRED_UNSPEC, + TCA_GRED_PARMS, + TCA_GRED_STAB, + TCA_GRED_DPS, + __TCA_GRED_MAX, +}; + +#define TCA_GRED_MAX (__TCA_GRED_MAX - 1) + +struct tc_gred_qopt { + __u32 limit; /* HARD maximal queue length (bytes) */ + __u32 qth_min; /* Min average length threshold (bytes) */ + __u32 qth_max; /* Max average length threshold (bytes) */ + __u32 DP; /* up to 2^32 DPs */ + __u32 backlog; + __u32 qave; + __u32 forced; + __u32 early; + __u32 other; + __u32 pdrop; + __u8 Wlog; /* log(W) */ + __u8 Plog; /* log(P_max/(qth_max-qth_min)) */ + __u8 Scell_log; /* cell size for idle damping */ + __u8 prio; /* prio of this VQ */ + __u32 packets; + __u32 bytesin; +}; + +/* gred setup */ +struct tc_gred_sopt { + __u32 DPs; + __u32 def_DP; + __u8 grio; + __u8 flags; + __u16 pad1; +}; + +/* CHOKe section */ + +enum { + TCA_CHOKE_UNSPEC, + TCA_CHOKE_PARMS, + TCA_CHOKE_STAB, + __TCA_CHOKE_MAX, +}; + +#define TCA_CHOKE_MAX (__TCA_CHOKE_MAX - 1) + +struct tc_choke_qopt { + __u32 limit; /* Hard queue length (packets) */ + __u32 qth_min; /* Min average threshold (packets) */ + __u32 qth_max; /* Max average threshold (packets) */ + unsigned char Wlog; /* log(W) */ + unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ + unsigned char Scell_log; /* cell size for idle damping */ + unsigned char flags; /* see RED flags */ +}; + +struct tc_choke_xstats { + __u32 early; /* Early drops */ + __u32 pdrop; /* Drops due to queue limits */ + __u32 other; /* Drops due to drop() calls */ + __u32 marked; /* Marked packets */ + __u32 matched; /* Drops due to flow match */ +}; + +/* HTB section */ +#define TC_HTB_NUMPRIO 8 +#define TC_HTB_MAXDEPTH 8 +#define TC_HTB_PROTOVER 3 /* the same as HTB and TC's major */ + +struct tc_htb_opt { + struct tc_ratespec rate; + struct tc_ratespec ceil; + __u32 buffer; + __u32 cbuffer; + __u32 quantum; + __u32 level; /* out only */ + __u32 prio; +}; +struct tc_htb_glob { + __u32 version; /* to match HTB/TC */ + __u32 rate2quantum; /* bps->quantum divisor */ + __u32 defcls; /* default class number */ + __u32 debug; /* debug flags */ + + /* stats */ + __u32 direct_pkts; /* count of non shapped packets */ +}; +enum { + TCA_HTB_UNSPEC, + TCA_HTB_PARMS, + TCA_HTB_INIT, + TCA_HTB_CTAB, + TCA_HTB_RTAB, + __TCA_HTB_MAX, +}; + +#define TCA_HTB_MAX (__TCA_HTB_MAX - 1) + +struct tc_htb_xstats { + __u32 lends; + __u32 borrows; + __u32 giants; /* too big packets (rate will not be accurate) */ + __u32 tokens; + __u32 ctokens; +}; + +/* HFSC section */ + +struct tc_hfsc_qopt { + __u16 defcls; /* default class */ +}; + +struct tc_service_curve { + __u32 m1; /* slope of the first segment in bps */ + __u32 d; /* x-projection of the first segment in us */ + __u32 m2; /* slope of the second segment in bps */ +}; + +struct tc_hfsc_stats { + __u64 work; /* total work done */ + __u64 rtwork; /* work done by real-time criteria */ + __u32 period; /* current period */ + __u32 level; /* class level in hierarchy */ +}; + +enum { + TCA_HFSC_UNSPEC, + TCA_HFSC_RSC, + TCA_HFSC_FSC, + TCA_HFSC_USC, + __TCA_HFSC_MAX, +}; + +#define TCA_HFSC_MAX (__TCA_HFSC_MAX - 1) + + +/* CBQ section */ + +#define TC_CBQ_MAXPRIO 8 +#define TC_CBQ_MAXLEVEL 8 +#define TC_CBQ_DEF_EWMA 5 + +struct tc_cbq_lssopt { + unsigned char change; + unsigned char flags; +#define TCF_CBQ_LSS_BOUNDED 1 +#define TCF_CBQ_LSS_ISOLATED 2 + unsigned char ewma_log; + unsigned char level; +#define TCF_CBQ_LSS_FLAGS 1 +#define TCF_CBQ_LSS_EWMA 2 +#define TCF_CBQ_LSS_MAXIDLE 4 +#define TCF_CBQ_LSS_MINIDLE 8 +#define TCF_CBQ_LSS_OFFTIME 0x10 +#define TCF_CBQ_LSS_AVPKT 0x20 + __u32 maxidle; + __u32 minidle; + __u32 offtime; + __u32 avpkt; +}; + +struct tc_cbq_wrropt { + unsigned char flags; + unsigned char priority; + unsigned char cpriority; + unsigned char __reserved; + __u32 allot; + __u32 weight; +}; + +struct tc_cbq_ovl { + unsigned char strategy; +#define TC_CBQ_OVL_CLASSIC 0 +#define TC_CBQ_OVL_DELAY 1 +#define TC_CBQ_OVL_LOWPRIO 2 +#define TC_CBQ_OVL_DROP 3 +#define TC_CBQ_OVL_RCLASSIC 4 + unsigned char priority2; + __u16 pad; + __u32 penalty; +}; + +struct tc_cbq_police { + unsigned char police; + unsigned char __res1; + unsigned short __res2; +}; + +struct tc_cbq_fopt { + __u32 split; + __u32 defmap; + __u32 defchange; +}; + +struct tc_cbq_xstats { + __u32 borrows; + __u32 overactions; + __s32 avgidle; + __s32 undertime; +}; + +enum { + TCA_CBQ_UNSPEC, + TCA_CBQ_LSSOPT, + TCA_CBQ_WRROPT, + TCA_CBQ_FOPT, + TCA_CBQ_OVL_STRATEGY, + TCA_CBQ_RATE, + TCA_CBQ_RTAB, + TCA_CBQ_POLICE, + __TCA_CBQ_MAX, +}; + +#define TCA_CBQ_MAX (__TCA_CBQ_MAX - 1) + +/* dsmark section */ + +enum { + TCA_DSMARK_UNSPEC, + TCA_DSMARK_INDICES, + TCA_DSMARK_DEFAULT_INDEX, + TCA_DSMARK_SET_TC_INDEX, + TCA_DSMARK_MASK, + TCA_DSMARK_VALUE, + __TCA_DSMARK_MAX, +}; + +#define TCA_DSMARK_MAX (__TCA_DSMARK_MAX - 1) + +/* ATM section */ + +enum { + TCA_ATM_UNSPEC, + TCA_ATM_FD, /* file/socket descriptor */ + TCA_ATM_PTR, /* pointer to descriptor - later */ + TCA_ATM_HDR, /* LL header */ + TCA_ATM_EXCESS, /* excess traffic class (0 for CLP) */ + TCA_ATM_ADDR, /* PVC address (for output only) */ + TCA_ATM_STATE, /* VC state (ATM_VS_*; for output only) */ + __TCA_ATM_MAX, +}; + +#define TCA_ATM_MAX (__TCA_ATM_MAX - 1) + +/* Network emulator */ + +enum { + TCA_NETEM_UNSPEC, + TCA_NETEM_CORR, + TCA_NETEM_DELAY_DIST, + TCA_NETEM_REORDER, + TCA_NETEM_CORRUPT, + TCA_NETEM_LOSS, + __TCA_NETEM_MAX, +}; + +#define TCA_NETEM_MAX (__TCA_NETEM_MAX - 1) + +struct tc_netem_qopt { + __u32 latency; /* added delay (us) */ + __u32 limit; /* fifo limit (packets) */ + __u32 loss; /* random packet loss (0=none ~0=100%) */ + __u32 gap; /* re-ordering gap (0 for none) */ + __u32 duplicate; /* random packet dup (0=none ~0=100%) */ + __u32 jitter; /* random jitter in latency (us) */ +}; + +struct tc_netem_corr { + __u32 delay_corr; /* delay correlation */ + __u32 loss_corr; /* packet loss correlation */ + __u32 dup_corr; /* duplicate correlation */ +}; + +struct tc_netem_reorder { + __u32 probability; + __u32 correlation; +}; + +struct tc_netem_corrupt { + __u32 probability; + __u32 correlation; +}; + +enum { + NETEM_LOSS_UNSPEC, + NETEM_LOSS_GI, /* General Intuitive - 4 state model */ + NETEM_LOSS_GE, /* Gilbert Elliot models */ + __NETEM_LOSS_MAX +}; +#define NETEM_LOSS_MAX (__NETEM_LOSS_MAX - 1) + +/* State transition probablities for 4 state model */ +struct tc_netem_gimodel { + __u32 p13; + __u32 p31; + __u32 p32; + __u32 p14; + __u32 p23; +}; + +/* Gilbert-Elliot models */ +struct tc_netem_gemodel { + __u32 p; + __u32 r; + __u32 h; + __u32 k1; +}; + +#define NETEM_DIST_SCALE 8192 +#define NETEM_DIST_MAX 16384 + +/* DRR */ + +enum { + TCA_DRR_UNSPEC, + TCA_DRR_QUANTUM, + __TCA_DRR_MAX +}; + +#define TCA_DRR_MAX (__TCA_DRR_MAX - 1) + +struct tc_drr_stats { + __u32 deficit; +}; + +/* MQPRIO */ +#define TC_QOPT_BITMASK 15 +#define TC_QOPT_MAX_QUEUE 16 + +struct tc_mqprio_qopt { + __u8 num_tc; + __u8 prio_tc_map[TC_QOPT_BITMASK + 1]; + __u8 hw; + __u16 count[TC_QOPT_MAX_QUEUE]; + __u16 offset[TC_QOPT_MAX_QUEUE]; +}; + +/* SFB */ + +enum { + TCA_SFB_UNSPEC, + TCA_SFB_PARMS, + __TCA_SFB_MAX, +}; + +#define TCA_SFB_MAX (__TCA_SFB_MAX - 1) + +/* + * Note: increment, decrement are Q0.16 fixed-point values. + */ +struct tc_sfb_qopt { + __u32 rehash_interval; /* delay between hash move, in ms */ + __u32 warmup_time; /* double buffering warmup time in ms (warmup_time < rehash_interval) */ + __u32 max; /* max len of qlen_min */ + __u32 bin_size; /* maximum queue length per bin */ + __u32 increment; /* probability increment, (d1 in Blue) */ + __u32 decrement; /* probability decrement, (d2 in Blue) */ + __u32 limit; /* max SFB queue length */ + __u32 penalty_rate; /* inelastic flows are rate limited to 'rate' pps */ + __u32 penalty_burst; +}; + +struct tc_sfb_xstats { + __u32 earlydrop; + __u32 penaltydrop; + __u32 bucketdrop; + __u32 queuedrop; + __u32 childdrop; /* drops in child qdisc */ + __u32 marked; + __u32 maxqlen; + __u32 maxprob; + __u32 avgprob; +}; + +#define SFB_MAX_PROB 0xFFFF + +/* QFQ */ +enum { + TCA_QFQ_UNSPEC, + TCA_QFQ_WEIGHT, + TCA_QFQ_LMAX, + __TCA_QFQ_MAX +}; + +#define TCA_QFQ_MAX (__TCA_QFQ_MAX - 1) + +struct tc_qfq_stats { + __u32 weight; + __u32 lmax; +}; + +#endif diff --git a/libnetwork/libnl3/include/linux/rtnetlink.h b/libnetwork/libnl3/include/linux/rtnetlink.h new file mode 100644 index 0000000..2363c18 --- /dev/null +++ b/libnetwork/libnl3/include/linux/rtnetlink.h @@ -0,0 +1,605 @@ +#ifndef __LINUX_RTNETLINK_H +#define __LINUX_RTNETLINK_H + +#include +#include +#include +#include +#include + +/* rtnetlink families. Values up to 127 are reserved for real address + * families, values above 128 may be used arbitrarily. + */ +#define RTNL_FAMILY_IPMR 128 +#define RTNL_FAMILY_IP6MR 129 +#define RTNL_FAMILY_MAX 129 + +/**** + * Routing/neighbour discovery messages. + ****/ + +/* Types of messages */ + +enum { + RTM_BASE = 16, +#define RTM_BASE RTM_BASE + + RTM_NEWLINK = 16, +#define RTM_NEWLINK RTM_NEWLINK + RTM_DELLINK, +#define RTM_DELLINK RTM_DELLINK + RTM_GETLINK, +#define RTM_GETLINK RTM_GETLINK + RTM_SETLINK, +#define RTM_SETLINK RTM_SETLINK + + RTM_NEWADDR = 20, +#define RTM_NEWADDR RTM_NEWADDR + RTM_DELADDR, +#define RTM_DELADDR RTM_DELADDR + RTM_GETADDR, +#define RTM_GETADDR RTM_GETADDR + + RTM_NEWROUTE = 24, +#define RTM_NEWROUTE RTM_NEWROUTE + RTM_DELROUTE, +#define RTM_DELROUTE RTM_DELROUTE + RTM_GETROUTE, +#define RTM_GETROUTE RTM_GETROUTE + + RTM_NEWNEIGH = 28, +#define RTM_NEWNEIGH RTM_NEWNEIGH + RTM_DELNEIGH, +#define RTM_DELNEIGH RTM_DELNEIGH + RTM_GETNEIGH, +#define RTM_GETNEIGH RTM_GETNEIGH + + RTM_NEWRULE = 32, +#define RTM_NEWRULE RTM_NEWRULE + RTM_DELRULE, +#define RTM_DELRULE RTM_DELRULE + RTM_GETRULE, +#define RTM_GETRULE RTM_GETRULE + + RTM_NEWQDISC = 36, +#define RTM_NEWQDISC RTM_NEWQDISC + RTM_DELQDISC, +#define RTM_DELQDISC RTM_DELQDISC + RTM_GETQDISC, +#define RTM_GETQDISC RTM_GETQDISC + + RTM_NEWTCLASS = 40, +#define RTM_NEWTCLASS RTM_NEWTCLASS + RTM_DELTCLASS, +#define RTM_DELTCLASS RTM_DELTCLASS + RTM_GETTCLASS, +#define RTM_GETTCLASS RTM_GETTCLASS + + RTM_NEWTFILTER = 44, +#define RTM_NEWTFILTER RTM_NEWTFILTER + RTM_DELTFILTER, +#define RTM_DELTFILTER RTM_DELTFILTER + RTM_GETTFILTER, +#define RTM_GETTFILTER RTM_GETTFILTER + + RTM_NEWACTION = 48, +#define RTM_NEWACTION RTM_NEWACTION + RTM_DELACTION, +#define RTM_DELACTION RTM_DELACTION + RTM_GETACTION, +#define RTM_GETACTION RTM_GETACTION + + RTM_NEWPREFIX = 52, +#define RTM_NEWPREFIX RTM_NEWPREFIX + + RTM_GETMULTICAST = 58, +#define RTM_GETMULTICAST RTM_GETMULTICAST + + RTM_GETANYCAST = 62, +#define RTM_GETANYCAST RTM_GETANYCAST + + RTM_NEWNEIGHTBL = 64, +#define RTM_NEWNEIGHTBL RTM_NEWNEIGHTBL + RTM_GETNEIGHTBL = 66, +#define RTM_GETNEIGHTBL RTM_GETNEIGHTBL + RTM_SETNEIGHTBL, +#define RTM_SETNEIGHTBL RTM_SETNEIGHTBL + + RTM_NEWNDUSEROPT = 68, +#define RTM_NEWNDUSEROPT RTM_NEWNDUSEROPT + + RTM_NEWADDRLABEL = 72, +#define RTM_NEWADDRLABEL RTM_NEWADDRLABEL + RTM_DELADDRLABEL, +#define RTM_DELADDRLABEL RTM_DELADDRLABEL + RTM_GETADDRLABEL, +#define RTM_GETADDRLABEL RTM_GETADDRLABEL + + RTM_GETDCB = 78, +#define RTM_GETDCB RTM_GETDCB + RTM_SETDCB, +#define RTM_SETDCB RTM_SETDCB + + __RTM_MAX, +#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) +}; + +#define RTM_NR_MSGTYPES (RTM_MAX + 1 - RTM_BASE) +#define RTM_NR_FAMILIES (RTM_NR_MSGTYPES >> 2) +#define RTM_FAM(cmd) (((cmd) - RTM_BASE) >> 2) + +/* + Generic structure for encapsulation of optional route information. + It is reminiscent of sockaddr, but with sa_family replaced + with attribute type. + */ + +struct rtattr { + unsigned short rta_len; + unsigned short rta_type; +}; + +/* Macros to handle rtattributes */ + +#define RTA_ALIGNTO 4 +#define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) ) +#define RTA_OK(rta,len) ((len) >= (int)sizeof(struct rtattr) && \ + (rta)->rta_len >= sizeof(struct rtattr) && \ + (rta)->rta_len <= (len)) +#define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), \ + (struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len))) +#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len)) +#define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len)) +#define RTA_DATA(rta) ((void*)(((char*)(rta)) + RTA_LENGTH(0))) +#define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0)) + + + + +/****************************************************************************** + * Definitions used in routing table administration. + ****/ + +struct rtmsg { + unsigned char rtm_family; + unsigned char rtm_dst_len; + unsigned char rtm_src_len; + unsigned char rtm_tos; + + unsigned char rtm_table; /* Routing table id */ + unsigned char rtm_protocol; /* Routing protocol; see below */ + unsigned char rtm_scope; /* See below */ + unsigned char rtm_type; /* See below */ + + unsigned rtm_flags; +}; + +/* rtm_type */ + +enum { + RTN_UNSPEC, + RTN_UNICAST, /* Gateway or direct route */ + RTN_LOCAL, /* Accept locally */ + RTN_BROADCAST, /* Accept locally as broadcast, + send as broadcast */ + RTN_ANYCAST, /* Accept locally as broadcast, + but send as unicast */ + RTN_MULTICAST, /* Multicast route */ + RTN_BLACKHOLE, /* Drop */ + RTN_UNREACHABLE, /* Destination is unreachable */ + RTN_PROHIBIT, /* Administratively prohibited */ + RTN_THROW, /* Not in this table */ + RTN_NAT, /* Translate this address */ + RTN_XRESOLVE, /* Use external resolver */ + __RTN_MAX +}; + +#define RTN_MAX (__RTN_MAX - 1) + + +/* rtm_protocol */ + +#define RTPROT_UNSPEC 0 +#define RTPROT_REDIRECT 1 /* Route installed by ICMP redirects; + not used by current IPv4 */ +#define RTPROT_KERNEL 2 /* Route installed by kernel */ +#define RTPROT_BOOT 3 /* Route installed during boot */ +#define RTPROT_STATIC 4 /* Route installed by administrator */ + +/* Values of protocol >= RTPROT_STATIC are not interpreted by kernel; + they are just passed from user and back as is. + It will be used by hypothetical multiple routing daemons. + Note that protocol values should be standardized in order to + avoid conflicts. + */ + +#define RTPROT_GATED 8 /* Apparently, GateD */ +#define RTPROT_RA 9 /* RDISC/ND router advertisements */ +#define RTPROT_MRT 10 /* Merit MRT */ +#define RTPROT_ZEBRA 11 /* Zebra */ +#define RTPROT_BIRD 12 /* BIRD */ +#define RTPROT_DNROUTED 13 /* DECnet routing daemon */ +#define RTPROT_XORP 14 /* XORP */ +#define RTPROT_NTK 15 /* Netsukuku */ +#define RTPROT_DHCP 16 /* DHCP client */ + +/* rtm_scope + + Really it is not scope, but sort of distance to the destination. + NOWHERE are reserved for not existing destinations, HOST is our + local addresses, LINK are destinations, located on directly attached + link and UNIVERSE is everywhere in the Universe. + + Intermediate values are also possible f.e. interior routes + could be assigned a value between UNIVERSE and LINK. +*/ + +enum rt_scope_t { + RT_SCOPE_UNIVERSE=0, +/* User defined values */ + RT_SCOPE_SITE=200, + RT_SCOPE_LINK=253, + RT_SCOPE_HOST=254, + RT_SCOPE_NOWHERE=255 +}; + +/* rtm_flags */ + +#define RTM_F_NOTIFY 0x100 /* Notify user of route change */ +#define RTM_F_CLONED 0x200 /* This route is cloned */ +#define RTM_F_EQUALIZE 0x400 /* Multipath equalizer: NI */ +#define RTM_F_PREFIX 0x800 /* Prefix addresses */ + +/* Reserved table identifiers */ + +enum rt_class_t { + RT_TABLE_UNSPEC=0, +/* User defined values */ + RT_TABLE_COMPAT=252, + RT_TABLE_DEFAULT=253, + RT_TABLE_MAIN=254, + RT_TABLE_LOCAL=255, + RT_TABLE_MAX=0xFFFFFFFF +}; + + +/* Routing message attributes */ + +enum rtattr_type_t { + RTA_UNSPEC, + RTA_DST, + RTA_SRC, + RTA_IIF, + RTA_OIF, + RTA_GATEWAY, + RTA_PRIORITY, + RTA_PREFSRC, + RTA_METRICS, + RTA_MULTIPATH, + RTA_PROTOINFO, /* no longer used */ + RTA_FLOW, + RTA_CACHEINFO, + RTA_SESSION, /* no longer used */ + RTA_MP_ALGO, /* no longer used */ + RTA_TABLE, + RTA_MARK, + __RTA_MAX +}; + +#define RTA_MAX (__RTA_MAX - 1) + +#define RTM_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtmsg)))) +#define RTM_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtmsg)) + +/* RTM_MULTIPATH --- array of struct rtnexthop. + * + * "struct rtnexthop" describes all necessary nexthop information, + * i.e. parameters of path to a destination via this nexthop. + * + * At the moment it is impossible to set different prefsrc, mtu, window + * and rtt for different paths from multipath. + */ + +struct rtnexthop { + unsigned short rtnh_len; + unsigned char rtnh_flags; + unsigned char rtnh_hops; + int rtnh_ifindex; +}; + +/* rtnh_flags */ + +#define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */ +#define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */ +#define RTNH_F_ONLINK 4 /* Gateway is forced on link */ + +/* Macros to handle hexthops */ + +#define RTNH_ALIGNTO 4 +#define RTNH_ALIGN(len) ( ((len)+RTNH_ALIGNTO-1) & ~(RTNH_ALIGNTO-1) ) +#define RTNH_OK(rtnh,len) ((rtnh)->rtnh_len >= sizeof(struct rtnexthop) && \ + ((int)(rtnh)->rtnh_len) <= (len)) +#define RTNH_NEXT(rtnh) ((struct rtnexthop*)(((char*)(rtnh)) + RTNH_ALIGN((rtnh)->rtnh_len))) +#define RTNH_LENGTH(len) (RTNH_ALIGN(sizeof(struct rtnexthop)) + (len)) +#define RTNH_SPACE(len) RTNH_ALIGN(RTNH_LENGTH(len)) +#define RTNH_DATA(rtnh) ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0))) + +/* RTM_CACHEINFO */ + +struct rta_cacheinfo { + __u32 rta_clntref; + __u32 rta_lastuse; + __s32 rta_expires; + __u32 rta_error; + __u32 rta_used; + +#define RTNETLINK_HAVE_PEERINFO 1 + __u32 rta_id; + __u32 rta_ts; + __u32 rta_tsage; +}; + +/* RTM_METRICS --- array of struct rtattr with types of RTAX_* */ + +enum { + RTAX_UNSPEC, +#define RTAX_UNSPEC RTAX_UNSPEC + RTAX_LOCK, +#define RTAX_LOCK RTAX_LOCK + RTAX_MTU, +#define RTAX_MTU RTAX_MTU + RTAX_WINDOW, +#define RTAX_WINDOW RTAX_WINDOW + RTAX_RTT, +#define RTAX_RTT RTAX_RTT + RTAX_RTTVAR, +#define RTAX_RTTVAR RTAX_RTTVAR + RTAX_SSTHRESH, +#define RTAX_SSTHRESH RTAX_SSTHRESH + RTAX_CWND, +#define RTAX_CWND RTAX_CWND + RTAX_ADVMSS, +#define RTAX_ADVMSS RTAX_ADVMSS + RTAX_REORDERING, +#define RTAX_REORDERING RTAX_REORDERING + RTAX_HOPLIMIT, +#define RTAX_HOPLIMIT RTAX_HOPLIMIT + RTAX_INITCWND, +#define RTAX_INITCWND RTAX_INITCWND + RTAX_FEATURES, +#define RTAX_FEATURES RTAX_FEATURES + RTAX_RTO_MIN, +#define RTAX_RTO_MIN RTAX_RTO_MIN + RTAX_INITRWND, +#define RTAX_INITRWND RTAX_INITRWND + __RTAX_MAX +}; + +#define RTAX_MAX (__RTAX_MAX - 1) + +#define RTAX_FEATURE_ECN 0x00000001 +#define RTAX_FEATURE_SACK 0x00000002 +#define RTAX_FEATURE_TIMESTAMP 0x00000004 +#define RTAX_FEATURE_ALLFRAG 0x00000008 + +struct rta_session { + __u8 proto; + __u8 pad1; + __u16 pad2; + + union { + struct { + __u16 sport; + __u16 dport; + } ports; + + struct { + __u8 type; + __u8 code; + __u16 ident; + } icmpt; + + __u32 spi; + } u; +}; + +/**** + * General form of address family dependent message. + ****/ + +struct rtgenmsg { + unsigned char rtgen_family; +}; + +/***************************************************************** + * Link layer specific messages. + ****/ + +/* struct ifinfomsg + * passes link level specific information, not dependent + * on network protocol. + */ + +struct ifinfomsg { + unsigned char ifi_family; + unsigned char __ifi_pad; + unsigned short ifi_type; /* ARPHRD_* */ + int ifi_index; /* Link index */ + unsigned ifi_flags; /* IFF_* flags */ + unsigned ifi_change; /* IFF_* change mask */ +}; + +/******************************************************************** + * prefix information + ****/ + +struct prefixmsg { + unsigned char prefix_family; + unsigned char prefix_pad1; + unsigned short prefix_pad2; + int prefix_ifindex; + unsigned char prefix_type; + unsigned char prefix_len; + unsigned char prefix_flags; + unsigned char prefix_pad3; +}; + +enum +{ + PREFIX_UNSPEC, + PREFIX_ADDRESS, + PREFIX_CACHEINFO, + __PREFIX_MAX +}; + +#define PREFIX_MAX (__PREFIX_MAX - 1) + +struct prefix_cacheinfo { + __u32 preferred_time; + __u32 valid_time; +}; + + +/***************************************************************** + * Traffic control messages. + ****/ + +struct tcmsg { + unsigned char tcm_family; + unsigned char tcm__pad1; + unsigned short tcm__pad2; + int tcm_ifindex; + __u32 tcm_handle; + __u32 tcm_parent; + __u32 tcm_info; +}; + +enum { + TCA_UNSPEC, + TCA_KIND, + TCA_OPTIONS, + TCA_STATS, + TCA_XSTATS, + TCA_RATE, + TCA_FCNT, + TCA_STATS2, + TCA_STAB, + __TCA_MAX +}; + +#define TCA_MAX (__TCA_MAX - 1) + +#define TCA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg)))) +#define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg)) + +/******************************************************************** + * Neighbor Discovery userland options + ****/ + +struct nduseroptmsg { + unsigned char nduseropt_family; + unsigned char nduseropt_pad1; + unsigned short nduseropt_opts_len; /* Total length of options */ + int nduseropt_ifindex; + __u8 nduseropt_icmp_type; + __u8 nduseropt_icmp_code; + unsigned short nduseropt_pad2; + unsigned int nduseropt_pad3; + /* Followed by one or more ND options */ +}; + +enum { + NDUSEROPT_UNSPEC, + NDUSEROPT_SRCADDR, + __NDUSEROPT_MAX +}; + +#define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1) + +#ifndef __KERNEL__ +/* RTnetlink multicast groups - backwards compatibility for userspace */ +#define RTMGRP_LINK 1 +#define RTMGRP_NOTIFY 2 +#define RTMGRP_NEIGH 4 +#define RTMGRP_TC 8 + +#define RTMGRP_IPV4_IFADDR 0x10 +#define RTMGRP_IPV4_MROUTE 0x20 +#define RTMGRP_IPV4_ROUTE 0x40 +#define RTMGRP_IPV4_RULE 0x80 + +#define RTMGRP_IPV6_IFADDR 0x100 +#define RTMGRP_IPV6_MROUTE 0x200 +#define RTMGRP_IPV6_ROUTE 0x400 +#define RTMGRP_IPV6_IFINFO 0x800 + +#define RTMGRP_DECnet_IFADDR 0x1000 +#define RTMGRP_DECnet_ROUTE 0x4000 + +#define RTMGRP_IPV6_PREFIX 0x20000 +#endif + +/* RTnetlink multicast groups */ +enum rtnetlink_groups { + RTNLGRP_NONE, +#define RTNLGRP_NONE RTNLGRP_NONE + RTNLGRP_LINK, +#define RTNLGRP_LINK RTNLGRP_LINK + RTNLGRP_NOTIFY, +#define RTNLGRP_NOTIFY RTNLGRP_NOTIFY + RTNLGRP_NEIGH, +#define RTNLGRP_NEIGH RTNLGRP_NEIGH + RTNLGRP_TC, +#define RTNLGRP_TC RTNLGRP_TC + RTNLGRP_IPV4_IFADDR, +#define RTNLGRP_IPV4_IFADDR RTNLGRP_IPV4_IFADDR + RTNLGRP_IPV4_MROUTE, +#define RTNLGRP_IPV4_MROUTE RTNLGRP_IPV4_MROUTE + RTNLGRP_IPV4_ROUTE, +#define RTNLGRP_IPV4_ROUTE RTNLGRP_IPV4_ROUTE + RTNLGRP_IPV4_RULE, +#define RTNLGRP_IPV4_RULE RTNLGRP_IPV4_RULE + RTNLGRP_IPV6_IFADDR, +#define RTNLGRP_IPV6_IFADDR RTNLGRP_IPV6_IFADDR + RTNLGRP_IPV6_MROUTE, +#define RTNLGRP_IPV6_MROUTE RTNLGRP_IPV6_MROUTE + RTNLGRP_IPV6_ROUTE, +#define RTNLGRP_IPV6_ROUTE RTNLGRP_IPV6_ROUTE + RTNLGRP_IPV6_IFINFO, +#define RTNLGRP_IPV6_IFINFO RTNLGRP_IPV6_IFINFO + RTNLGRP_DECnet_IFADDR, +#define RTNLGRP_DECnet_IFADDR RTNLGRP_DECnet_IFADDR + RTNLGRP_NOP2, + RTNLGRP_DECnet_ROUTE, +#define RTNLGRP_DECnet_ROUTE RTNLGRP_DECnet_ROUTE + RTNLGRP_DECnet_RULE, +#define RTNLGRP_DECnet_RULE RTNLGRP_DECnet_RULE + RTNLGRP_NOP4, + RTNLGRP_IPV6_PREFIX, +#define RTNLGRP_IPV6_PREFIX RTNLGRP_IPV6_PREFIX + RTNLGRP_IPV6_RULE, +#define RTNLGRP_IPV6_RULE RTNLGRP_IPV6_RULE + RTNLGRP_ND_USEROPT, +#define RTNLGRP_ND_USEROPT RTNLGRP_ND_USEROPT + RTNLGRP_PHONET_IFADDR, +#define RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_IFADDR + RTNLGRP_PHONET_ROUTE, +#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE + __RTNLGRP_MAX +}; +#define RTNLGRP_MAX (__RTNLGRP_MAX - 1) + +/* TC action piece */ +struct tcamsg { + unsigned char tca_family; + unsigned char tca__pad1; + unsigned short tca__pad2; +}; +#define TA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcamsg)))) +#define TA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcamsg)) +#define TCA_ACT_TAB 1 /* attr type must be >=1 */ +#define TCAA_MAX 1 + +/* End of information exported to user level */ + +#endif /* __LINUX_RTNETLINK_H */ diff --git a/libnetwork/libnl3/include/linux/snmp.h b/libnetwork/libnl3/include/linux/snmp.h new file mode 100644 index 0000000..12b2b18 --- /dev/null +++ b/libnetwork/libnl3/include/linux/snmp.h @@ -0,0 +1,270 @@ +/* + * Definitions for MIBs + * + * Author: Hideaki YOSHIFUJI + */ + +#ifndef _LINUX_SNMP_H +#define _LINUX_SNMP_H + +/* ipstats mib definitions */ +/* + * RFC 1213: MIB-II + * RFC 2011 (updates 1213): SNMPv2-MIB-IP + * RFC 2863: Interfaces Group MIB + * RFC 2465: IPv6 MIB: General Group + * draft-ietf-ipv6-rfc2011-update-10.txt: MIB for IP: IP Statistics Tables + */ +enum +{ + IPSTATS_MIB_NUM = 0, + IPSTATS_MIB_INPKTS, /* InReceives */ + IPSTATS_MIB_INHDRERRORS, /* InHdrErrors */ + IPSTATS_MIB_INTOOBIGERRORS, /* InTooBigErrors */ + IPSTATS_MIB_INNOROUTES, /* InNoRoutes */ + IPSTATS_MIB_INADDRERRORS, /* InAddrErrors */ + IPSTATS_MIB_INUNKNOWNPROTOS, /* InUnknownProtos */ + IPSTATS_MIB_INTRUNCATEDPKTS, /* InTruncatedPkts */ + IPSTATS_MIB_INDISCARDS, /* InDiscards */ + IPSTATS_MIB_INDELIVERS, /* InDelivers */ + IPSTATS_MIB_OUTFORWDATAGRAMS, /* OutForwDatagrams */ + IPSTATS_MIB_OUTPKTS, /* OutRequests */ + IPSTATS_MIB_OUTDISCARDS, /* OutDiscards */ + IPSTATS_MIB_OUTNOROUTES, /* OutNoRoutes */ + IPSTATS_MIB_REASMTIMEOUT, /* ReasmTimeout */ + IPSTATS_MIB_REASMREQDS, /* ReasmReqds */ + IPSTATS_MIB_REASMOKS, /* ReasmOKs */ + IPSTATS_MIB_REASMFAILS, /* ReasmFails */ + IPSTATS_MIB_FRAGOKS, /* FragOKs */ + IPSTATS_MIB_FRAGFAILS, /* FragFails */ + IPSTATS_MIB_FRAGCREATES, /* FragCreates */ + IPSTATS_MIB_INMCASTPKTS, /* InMcastPkts */ + IPSTATS_MIB_OUTMCASTPKTS, /* OutMcastPkts */ + IPSTATS_MIB_INBCASTPKTS, /* InBcastPkts */ + IPSTATS_MIB_OUTBCASTPKTS, /* OutBcastPkts */ + IPSTATS_MIB_INOCTETS, /* InOctets */ + IPSTATS_MIB_OUTOCTETS, /* OutOctets */ + IPSTATS_MIB_INMCASTOCTETS, /* InMcastOctets */ + IPSTATS_MIB_OUTMCASTOCTETS, /* OutMcastOctets */ + IPSTATS_MIB_INBCASTOCTETS, /* InBcastOctets */ + IPSTATS_MIB_OUTBCASTOCTETS, /* OutBcastOctets */ + __IPSTATS_MIB_MAX +}; + +/* icmp mib definitions */ +/* + * RFC 1213: MIB-II ICMP Group + * RFC 2011 (updates 1213): SNMPv2 MIB for IP: ICMP group + */ +enum +{ + ICMP_MIB_NUM = 0, + ICMP_MIB_INMSGS, /* InMsgs */ + ICMP_MIB_INERRORS, /* InErrors */ + ICMP_MIB_INDESTUNREACHS, /* InDestUnreachs */ + ICMP_MIB_INTIMEEXCDS, /* InTimeExcds */ + ICMP_MIB_INPARMPROBS, /* InParmProbs */ + ICMP_MIB_INSRCQUENCHS, /* InSrcQuenchs */ + ICMP_MIB_INREDIRECTS, /* InRedirects */ + ICMP_MIB_INECHOS, /* InEchos */ + ICMP_MIB_INECHOREPS, /* InEchoReps */ + ICMP_MIB_INTIMESTAMPS, /* InTimestamps */ + ICMP_MIB_INTIMESTAMPREPS, /* InTimestampReps */ + ICMP_MIB_INADDRMASKS, /* InAddrMasks */ + ICMP_MIB_INADDRMASKREPS, /* InAddrMaskReps */ + ICMP_MIB_OUTMSGS, /* OutMsgs */ + ICMP_MIB_OUTERRORS, /* OutErrors */ + ICMP_MIB_OUTDESTUNREACHS, /* OutDestUnreachs */ + ICMP_MIB_OUTTIMEEXCDS, /* OutTimeExcds */ + ICMP_MIB_OUTPARMPROBS, /* OutParmProbs */ + ICMP_MIB_OUTSRCQUENCHS, /* OutSrcQuenchs */ + ICMP_MIB_OUTREDIRECTS, /* OutRedirects */ + ICMP_MIB_OUTECHOS, /* OutEchos */ + ICMP_MIB_OUTECHOREPS, /* OutEchoReps */ + ICMP_MIB_OUTTIMESTAMPS, /* OutTimestamps */ + ICMP_MIB_OUTTIMESTAMPREPS, /* OutTimestampReps */ + ICMP_MIB_OUTADDRMASKS, /* OutAddrMasks */ + ICMP_MIB_OUTADDRMASKREPS, /* OutAddrMaskReps */ + __ICMP_MIB_MAX +}; + +#define __ICMPMSG_MIB_MAX 512 /* Out+In for all 8-bit ICMP types */ + +/* icmp6 mib definitions */ +/* + * RFC 2466: ICMPv6-MIB + */ +enum +{ + ICMP6_MIB_NUM = 0, + ICMP6_MIB_INMSGS, /* InMsgs */ + ICMP6_MIB_INERRORS, /* InErrors */ + ICMP6_MIB_OUTMSGS, /* OutMsgs */ + ICMP6_MIB_OUTERRORS, /* OutErrors */ + __ICMP6_MIB_MAX +}; + +#define __ICMP6MSG_MIB_MAX 512 /* Out+In for all 8-bit ICMPv6 types */ + +/* tcp mib definitions */ +/* + * RFC 1213: MIB-II TCP group + * RFC 2012 (updates 1213): SNMPv2-MIB-TCP + */ +enum +{ + TCP_MIB_NUM = 0, + TCP_MIB_RTOALGORITHM, /* RtoAlgorithm */ + TCP_MIB_RTOMIN, /* RtoMin */ + TCP_MIB_RTOMAX, /* RtoMax */ + TCP_MIB_MAXCONN, /* MaxConn */ + TCP_MIB_ACTIVEOPENS, /* ActiveOpens */ + TCP_MIB_PASSIVEOPENS, /* PassiveOpens */ + TCP_MIB_ATTEMPTFAILS, /* AttemptFails */ + TCP_MIB_ESTABRESETS, /* EstabResets */ + TCP_MIB_CURRESTAB, /* CurrEstab */ + TCP_MIB_INSEGS, /* InSegs */ + TCP_MIB_OUTSEGS, /* OutSegs */ + TCP_MIB_RETRANSSEGS, /* RetransSegs */ + TCP_MIB_INERRS, /* InErrs */ + TCP_MIB_OUTRSTS, /* OutRsts */ + __TCP_MIB_MAX +}; + +/* udp mib definitions */ +/* + * RFC 1213: MIB-II UDP group + * RFC 2013 (updates 1213): SNMPv2-MIB-UDP + */ +enum +{ + UDP_MIB_NUM = 0, + UDP_MIB_INDATAGRAMS, /* InDatagrams */ + UDP_MIB_NOPORTS, /* NoPorts */ + UDP_MIB_INERRORS, /* InErrors */ + UDP_MIB_OUTDATAGRAMS, /* OutDatagrams */ + UDP_MIB_RCVBUFERRORS, /* RcvbufErrors */ + UDP_MIB_SNDBUFERRORS, /* SndbufErrors */ + __UDP_MIB_MAX +}; + +/* linux mib definitions */ +enum +{ + LINUX_MIB_NUM = 0, + LINUX_MIB_SYNCOOKIESSENT, /* SyncookiesSent */ + LINUX_MIB_SYNCOOKIESRECV, /* SyncookiesRecv */ + LINUX_MIB_SYNCOOKIESFAILED, /* SyncookiesFailed */ + LINUX_MIB_EMBRYONICRSTS, /* EmbryonicRsts */ + LINUX_MIB_PRUNECALLED, /* PruneCalled */ + LINUX_MIB_RCVPRUNED, /* RcvPruned */ + LINUX_MIB_OFOPRUNED, /* OfoPruned */ + LINUX_MIB_OUTOFWINDOWICMPS, /* OutOfWindowIcmps */ + LINUX_MIB_LOCKDROPPEDICMPS, /* LockDroppedIcmps */ + LINUX_MIB_ARPFILTER, /* ArpFilter */ + LINUX_MIB_TIMEWAITED, /* TimeWaited */ + LINUX_MIB_TIMEWAITRECYCLED, /* TimeWaitRecycled */ + LINUX_MIB_TIMEWAITKILLED, /* TimeWaitKilled */ + LINUX_MIB_PAWSPASSIVEREJECTED, /* PAWSPassiveRejected */ + LINUX_MIB_PAWSACTIVEREJECTED, /* PAWSActiveRejected */ + LINUX_MIB_PAWSESTABREJECTED, /* PAWSEstabRejected */ + LINUX_MIB_DELAYEDACKS, /* DelayedACKs */ + LINUX_MIB_DELAYEDACKLOCKED, /* DelayedACKLocked */ + LINUX_MIB_DELAYEDACKLOST, /* DelayedACKLost */ + LINUX_MIB_LISTENOVERFLOWS, /* ListenOverflows */ + LINUX_MIB_LISTENDROPS, /* ListenDrops */ + LINUX_MIB_TCPPREQUEUED, /* TCPPrequeued */ + LINUX_MIB_TCPDIRECTCOPYFROMBACKLOG, /* TCPDirectCopyFromBacklog */ + LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE, /* TCPDirectCopyFromPrequeue */ + LINUX_MIB_TCPPREQUEUEDROPPED, /* TCPPrequeueDropped */ + LINUX_MIB_TCPHPHITS, /* TCPHPHits */ + LINUX_MIB_TCPHPHITSTOUSER, /* TCPHPHitsToUser */ + LINUX_MIB_TCPPUREACKS, /* TCPPureAcks */ + LINUX_MIB_TCPHPACKS, /* TCPHPAcks */ + LINUX_MIB_TCPRENORECOVERY, /* TCPRenoRecovery */ + LINUX_MIB_TCPSACKRECOVERY, /* TCPSackRecovery */ + LINUX_MIB_TCPSACKRENEGING, /* TCPSACKReneging */ + LINUX_MIB_TCPFACKREORDER, /* TCPFACKReorder */ + LINUX_MIB_TCPSACKREORDER, /* TCPSACKReorder */ + LINUX_MIB_TCPRENOREORDER, /* TCPRenoReorder */ + LINUX_MIB_TCPTSREORDER, /* TCPTSReorder */ + LINUX_MIB_TCPFULLUNDO, /* TCPFullUndo */ + LINUX_MIB_TCPPARTIALUNDO, /* TCPPartialUndo */ + LINUX_MIB_TCPDSACKUNDO, /* TCPDSACKUndo */ + LINUX_MIB_TCPLOSSUNDO, /* TCPLossUndo */ + LINUX_MIB_TCPLOSS, /* TCPLoss */ + LINUX_MIB_TCPLOSTRETRANSMIT, /* TCPLostRetransmit */ + LINUX_MIB_TCPRENOFAILURES, /* TCPRenoFailures */ + LINUX_MIB_TCPSACKFAILURES, /* TCPSackFailures */ + LINUX_MIB_TCPLOSSFAILURES, /* TCPLossFailures */ + LINUX_MIB_TCPFASTRETRANS, /* TCPFastRetrans */ + LINUX_MIB_TCPFORWARDRETRANS, /* TCPForwardRetrans */ + LINUX_MIB_TCPSLOWSTARTRETRANS, /* TCPSlowStartRetrans */ + LINUX_MIB_TCPTIMEOUTS, /* TCPTimeouts */ + LINUX_MIB_TCPRENORECOVERYFAIL, /* TCPRenoRecoveryFail */ + LINUX_MIB_TCPSACKRECOVERYFAIL, /* TCPSackRecoveryFail */ + LINUX_MIB_TCPSCHEDULERFAILED, /* TCPSchedulerFailed */ + LINUX_MIB_TCPRCVCOLLAPSED, /* TCPRcvCollapsed */ + LINUX_MIB_TCPDSACKOLDSENT, /* TCPDSACKOldSent */ + LINUX_MIB_TCPDSACKOFOSENT, /* TCPDSACKOfoSent */ + LINUX_MIB_TCPDSACKRECV, /* TCPDSACKRecv */ + LINUX_MIB_TCPDSACKOFORECV, /* TCPDSACKOfoRecv */ + LINUX_MIB_TCPABORTONSYN, /* TCPAbortOnSyn */ + LINUX_MIB_TCPABORTONDATA, /* TCPAbortOnData */ + LINUX_MIB_TCPABORTONCLOSE, /* TCPAbortOnClose */ + LINUX_MIB_TCPABORTONMEMORY, /* TCPAbortOnMemory */ + LINUX_MIB_TCPABORTONTIMEOUT, /* TCPAbortOnTimeout */ + LINUX_MIB_TCPABORTONLINGER, /* TCPAbortOnLinger */ + LINUX_MIB_TCPABORTFAILED, /* TCPAbortFailed */ + LINUX_MIB_TCPMEMORYPRESSURES, /* TCPMemoryPressures */ + LINUX_MIB_TCPSACKDISCARD, /* TCPSACKDiscard */ + LINUX_MIB_TCPDSACKIGNOREDOLD, /* TCPSACKIgnoredOld */ + LINUX_MIB_TCPDSACKIGNOREDNOUNDO, /* TCPSACKIgnoredNoUndo */ + LINUX_MIB_TCPSPURIOUSRTOS, /* TCPSpuriousRTOs */ + LINUX_MIB_TCPMD5NOTFOUND, /* TCPMD5NotFound */ + LINUX_MIB_TCPMD5UNEXPECTED, /* TCPMD5Unexpected */ + LINUX_MIB_SACKSHIFTED, + LINUX_MIB_SACKMERGED, + LINUX_MIB_SACKSHIFTFALLBACK, + LINUX_MIB_TCPBACKLOGDROP, + LINUX_MIB_TCPMINTTLDROP, /* RFC 5082 */ + LINUX_MIB_TCPDEFERACCEPTDROP, + LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */ + LINUX_MIB_TCPTIMEWAITOVERFLOW, /* TCPTimeWaitOverflow */ + __LINUX_MIB_MAX +}; + +/* linux Xfrm mib definitions */ +enum +{ + LINUX_MIB_XFRMNUM = 0, + LINUX_MIB_XFRMINERROR, /* XfrmInError */ + LINUX_MIB_XFRMINBUFFERERROR, /* XfrmInBufferError */ + LINUX_MIB_XFRMINHDRERROR, /* XfrmInHdrError */ + LINUX_MIB_XFRMINNOSTATES, /* XfrmInNoStates */ + LINUX_MIB_XFRMINSTATEPROTOERROR, /* XfrmInStateProtoError */ + LINUX_MIB_XFRMINSTATEMODEERROR, /* XfrmInStateModeError */ + LINUX_MIB_XFRMINSTATESEQERROR, /* XfrmInStateSeqError */ + LINUX_MIB_XFRMINSTATEEXPIRED, /* XfrmInStateExpired */ + LINUX_MIB_XFRMINSTATEMISMATCH, /* XfrmInStateMismatch */ + LINUX_MIB_XFRMINSTATEINVALID, /* XfrmInStateInvalid */ + LINUX_MIB_XFRMINTMPLMISMATCH, /* XfrmInTmplMismatch */ + LINUX_MIB_XFRMINNOPOLS, /* XfrmInNoPols */ + LINUX_MIB_XFRMINPOLBLOCK, /* XfrmInPolBlock */ + LINUX_MIB_XFRMINPOLERROR, /* XfrmInPolError */ + LINUX_MIB_XFRMOUTERROR, /* XfrmOutError */ + LINUX_MIB_XFRMOUTBUNDLEGENERROR, /* XfrmOutBundleGenError */ + LINUX_MIB_XFRMOUTBUNDLECHECKERROR, /* XfrmOutBundleCheckError */ + LINUX_MIB_XFRMOUTNOSTATES, /* XfrmOutNoStates */ + LINUX_MIB_XFRMOUTSTATEPROTOERROR, /* XfrmOutStateProtoError */ + LINUX_MIB_XFRMOUTSTATEMODEERROR, /* XfrmOutStateModeError */ + LINUX_MIB_XFRMOUTSTATESEQERROR, /* XfrmOutStateSeqError */ + LINUX_MIB_XFRMOUTSTATEEXPIRED, /* XfrmOutStateExpired */ + LINUX_MIB_XFRMOUTPOLBLOCK, /* XfrmOutPolBlock */ + LINUX_MIB_XFRMOUTPOLDEAD, /* XfrmOutPolDead */ + LINUX_MIB_XFRMOUTPOLERROR, /* XfrmOutPolError */ + LINUX_MIB_XFRMFWDHDRERROR, /* XfrmFwdHdrError*/ + __LINUX_MIB_XFRMMAX +}; + +#endif /* _LINUX_SNMP_H */ diff --git a/libnetwork/libnl3/include/linux/tc_ematch/tc_em_meta.h b/libnetwork/libnl3/include/linux/tc_ematch/tc_em_meta.h new file mode 100644 index 0000000..fe815e2 --- /dev/null +++ b/libnetwork/libnl3/include/linux/tc_ematch/tc_em_meta.h @@ -0,0 +1,89 @@ +#ifndef __LINUX_TC_EM_META_H +#define __LINUX_TC_EM_META_H + +enum { + TCA_EM_META_UNSPEC, + TCA_EM_META_HDR, + TCA_EM_META_LVALUE, + TCA_EM_META_RVALUE, + __TCA_EM_META_MAX +}; +#define TCA_EM_META_MAX (__TCA_EM_META_MAX - 1) + +struct tcf_meta_val { + __u16 kind; + __u8 shift; + __u8 op; +}; + +#define TCF_META_TYPE_MASK (0xf << 12) +#define TCF_META_TYPE(kind) (((kind) & TCF_META_TYPE_MASK) >> 12) +#define TCF_META_ID_MASK 0x7ff +#define TCF_META_ID(kind) ((kind) & TCF_META_ID_MASK) + +enum { + TCF_META_TYPE_VAR, + TCF_META_TYPE_INT, + __TCF_META_TYPE_MAX +}; +#define TCF_META_TYPE_MAX (__TCF_META_TYPE_MAX - 1) + +enum { + TCF_META_ID_VALUE, + TCF_META_ID_RANDOM, + TCF_META_ID_LOADAVG_0, + TCF_META_ID_LOADAVG_1, + TCF_META_ID_LOADAVG_2, + TCF_META_ID_DEV, + TCF_META_ID_PRIORITY, + TCF_META_ID_PROTOCOL, + TCF_META_ID_PKTTYPE, + TCF_META_ID_PKTLEN, + TCF_META_ID_DATALEN, + TCF_META_ID_MACLEN, + TCF_META_ID_NFMARK, + TCF_META_ID_TCINDEX, + TCF_META_ID_RTCLASSID, + TCF_META_ID_RTIIF, + TCF_META_ID_SK_FAMILY, + TCF_META_ID_SK_STATE, + TCF_META_ID_SK_REUSE, + TCF_META_ID_SK_BOUND_IF, + TCF_META_ID_SK_REFCNT, + TCF_META_ID_SK_SHUTDOWN, + TCF_META_ID_SK_PROTO, + TCF_META_ID_SK_TYPE, + TCF_META_ID_SK_RCVBUF, + TCF_META_ID_SK_RMEM_ALLOC, + TCF_META_ID_SK_WMEM_ALLOC, + TCF_META_ID_SK_OMEM_ALLOC, + TCF_META_ID_SK_WMEM_QUEUED, + TCF_META_ID_SK_RCV_QLEN, + TCF_META_ID_SK_SND_QLEN, + TCF_META_ID_SK_ERR_QLEN, + TCF_META_ID_SK_FORWARD_ALLOCS, + TCF_META_ID_SK_SNDBUF, + TCF_META_ID_SK_ALLOCS, + TCF_META_ID_SK_ROUTE_CAPS, + TCF_META_ID_SK_HASH, + TCF_META_ID_SK_LINGERTIME, + TCF_META_ID_SK_ACK_BACKLOG, + TCF_META_ID_SK_MAX_ACK_BACKLOG, + TCF_META_ID_SK_PRIO, + TCF_META_ID_SK_RCVLOWAT, + TCF_META_ID_SK_RCVTIMEO, + TCF_META_ID_SK_SNDTIMEO, + TCF_META_ID_SK_SENDMSG_OFF, + TCF_META_ID_SK_WRITE_PENDING, + TCF_META_ID_VLAN_TAG, + TCF_META_ID_RXHASH, + __TCF_META_ID_MAX +}; +#define TCF_META_ID_MAX (__TCF_META_ID_MAX - 1) + +struct tcf_meta_hdr { + struct tcf_meta_val left; + struct tcf_meta_val right; +}; + +#endif diff --git a/libnetwork/libnl3/include/netlink-generic.h b/libnetwork/libnl3/include/netlink-generic.h new file mode 100644 index 0000000..10aa2f0 --- /dev/null +++ b/libnetwork/libnl3/include/netlink-generic.h @@ -0,0 +1,20 @@ +/* + * netlink-generic.h Local Generic Netlink Interface + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_GENL_PRIV_H_ +#define NETLINK_GENL_PRIV_H_ + +#include +#include + +#define GENL_HDRSIZE(hdrlen) (GENL_HDRLEN + (hdrlen)) + +#endif diff --git a/libnetwork/libnl3/include/netlink-local.h b/libnetwork/libnl3/include/netlink-local.h new file mode 100644 index 0000000..01c611a --- /dev/null +++ b/libnetwork/libnl3/include/netlink-local.h @@ -0,0 +1,213 @@ +/* + * netlink-local.h Local Netlink Interface + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +#ifndef NETLINK_LOCAL_H_ +#define NETLINK_LOCAL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 +#endif + +#include + +/* local header copies */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +struct trans_tbl { + int i; + const char *a; +}; + +#define __ADD(id, name) { .i = id, .a = #name }, + +struct trans_list { + int i; + char *a; + struct nl_list_head list; +}; + +#define NL_DEBUG 1 + +#define NL_DBG(LVL,FMT,ARG...) \ + do { \ + if (LVL <= nl_debug) \ + fprintf(stderr, "DBG<" #LVL ">: " FMT, ##ARG); \ + } while (0) + +#define BUG() \ + do { \ + fprintf(stderr, "BUG: %s:%d\n", \ + __FILE__, __LINE__); \ + assert(0); \ + } while (0) + +#define APPBUG(msg) \ + do { \ + fprintf(stderr, "APPLICATION BUG: %s:%d:%s: %s\n", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, msg); \ + assert(0); \ + } while(0) + +extern int __nl_read_num_str_file(const char *path, + int (*cb)(long, const char *)); + +extern int __trans_list_add(int, const char *, struct nl_list_head *); +extern void __trans_list_clear(struct nl_list_head *); + +extern char *__type2str(int, char *, size_t, const struct trans_tbl *, size_t); +extern int __str2type(const char *, const struct trans_tbl *, size_t); + +extern char *__list_type2str(int, char *, size_t, struct nl_list_head *); +extern int __list_str2type(const char *, struct nl_list_head *); + +extern char *__flags2str(int, char *, size_t, const struct trans_tbl *, size_t); +extern int __str2flags(const char *, const struct trans_tbl *, size_t); + +extern void dump_from_ops(struct nl_object *, struct nl_dump_params *); + +static inline struct nl_cache *dp_cache(struct nl_object *obj) +{ + if (obj->ce_cache == NULL) + return nl_cache_mngt_require(obj->ce_ops->oo_name); + + return obj->ce_cache; +} + +static inline int nl_cb_call(struct nl_cb *cb, int type, struct nl_msg *msg) +{ + return cb->cb_set[type](msg, cb->cb_args[type]); +} + +#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0])) + +/* This is also defined in stddef.h */ +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +#define __init __attribute__ ((constructor)) +#define __exit __attribute__ ((destructor)) +#undef __deprecated +#define __deprecated __attribute__ ((deprecated)) + +#define min(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x < _y ? _x : _y; }) + +#define max(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x > _y ? _x : _y; }) + +#define min_t(type,x,y) \ + ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) +#define max_t(type,x,y) \ + ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) + +extern int nl_cache_parse(struct nl_cache_ops *, struct sockaddr_nl *, + struct nlmsghdr *, struct nl_parser_param *); + + +static inline void rtnl_copy_ratespec(struct rtnl_ratespec *dst, + struct tc_ratespec *src) +{ + dst->rs_cell_log = src->cell_log; + dst->rs_overhead = src->overhead; + dst->rs_cell_align = src->cell_align; + dst->rs_mpu = src->mpu; + dst->rs_rate = src->rate; +} + +static inline void rtnl_rcopy_ratespec(struct tc_ratespec *dst, + struct rtnl_ratespec *src) +{ + dst->cell_log = src->rs_cell_log; + dst->overhead = src->rs_overhead; + dst->cell_align = src->rs_cell_align; + dst->mpu = src->rs_mpu; + dst->rate = src->rs_rate; +} + +static inline char *nl_cache_name(struct nl_cache *cache) +{ + return cache->c_ops ? cache->c_ops->co_name : "unknown"; +} + +#define GENL_FAMILY(id, name) \ + { \ + { id, NL_ACT_UNSPEC, name }, \ + END_OF_MSGTYPES_LIST, \ + } + +static inline int wait_for_ack(struct nl_sock *sk) +{ + if (sk->s_flags & NL_NO_AUTO_ACK) + return 0; + else + return nl_wait_for_ack(sk); +} + +static inline int build_sysconf_path(char **strp, const char *filename) +{ + char *sysconfdir; + + sysconfdir = getenv("NLSYSCONFDIR"); + + if (!sysconfdir) + sysconfdir = SYSCONFDIR; + + return asprintf(strp, "%s/%s", sysconfdir, filename); +} + +#endif diff --git a/libnetwork/libnl3/include/netlink-tc.h b/libnetwork/libnl3/include/netlink-tc.h new file mode 100644 index 0000000..3e44642 --- /dev/null +++ b/libnetwork/libnl3/include/netlink-tc.h @@ -0,0 +1,55 @@ +/* + * netlink-tc.h Local Traffic Control Interface + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2010 Thomas Graf + */ + +#ifndef NETLINK_TC_PRIV_H_ +#define NETLINK_TC_PRIV_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define TCA_ATTR_HANDLE 0x0001 +#define TCA_ATTR_PARENT 0x0002 +#define TCA_ATTR_IFINDEX 0x0004 +#define TCA_ATTR_KIND 0x0008 +#define TCA_ATTR_FAMILY 0x0010 +#define TCA_ATTR_INFO 0x0020 +#define TCA_ATTR_OPTS 0x0040 +#define TCA_ATTR_STATS 0x0080 +#define TCA_ATTR_XSTATS 0x0100 +#define TCA_ATTR_LINK 0x0200 +#define TCA_ATTR_MTU 0x0400 +#define TCA_ATTR_MPU 0x0800 +#define TCA_ATTR_OVERHEAD 0x1000 +#define TCA_ATTR_LINKTYPE 0x2000 +#define TCA_ATTR_MAX TCA_ATTR_LINKTYPE + +extern int tca_parse(struct nlattr **, int, struct rtnl_tc *, + struct nla_policy *); + +#define RTNL_TC_RTABLE_SIZE 256 + +extern int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *, + uint32_t *); + + +static inline void *tca_xstats(struct rtnl_tc *tca) +{ + return tca->tc_xstats->d_data; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink-types.h b/libnetwork/libnl3/include/netlink-types.h new file mode 100644 index 0000000..750c897 --- /dev/null +++ b/libnetwork/libnl3/include/netlink-types.h @@ -0,0 +1,846 @@ +/* + * netlink-types.h Netlink Types (Private) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_LOCAL_TYPES_H_ +#define NETLINK_LOCAL_TYPES_H_ + +#include +#include +#include +#include +#include +#include + +#define NL_SOCK_BUFSIZE_SET (1<<0) +#define NL_SOCK_PASSCRED (1<<1) +#define NL_OWN_PORT (1<<2) +#define NL_MSG_PEEK (1<<3) +#define NL_NO_AUTO_ACK (1<<4) + +#define NL_MSG_CRED_PRESENT 1 + +struct nl_cache_ops; +struct nl_sock; +struct nl_object; + +struct nl_cb +{ + nl_recvmsg_msg_cb_t cb_set[NL_CB_TYPE_MAX+1]; + void * cb_args[NL_CB_TYPE_MAX+1]; + + nl_recvmsg_err_cb_t cb_err; + void * cb_err_arg; + + /** May be used to replace nl_recvmsgs with your own implementation + * in all internal calls to nl_recvmsgs. */ + int (*cb_recvmsgs_ow)(struct nl_sock *, + struct nl_cb *); + + /** Overwrite internal calls to nl_recv, must return the number of + * octets read and allocate a buffer for the received data. */ + int (*cb_recv_ow)(struct nl_sock *, + struct sockaddr_nl *, + unsigned char **, + struct ucred **); + + /** Overwrites internal calls to nl_send, must send the netlink + * message. */ + int (*cb_send_ow)(struct nl_sock *, + struct nl_msg *); + + int cb_refcnt; +}; + +struct nl_sock +{ + struct sockaddr_nl s_local; + struct sockaddr_nl s_peer; + int s_fd; + int s_proto; + unsigned int s_seq_next; + unsigned int s_seq_expect; + int s_flags; + struct nl_cb * s_cb; +}; + +struct nl_cache +{ + struct nl_list_head c_items; + int c_nitems; + int c_iarg1; + int c_iarg2; + struct nl_cache_ops * c_ops; +}; + +struct nl_cache_assoc +{ + struct nl_cache * ca_cache; + change_func_t ca_change; + void * ca_change_data; +}; + +struct nl_cache_mngr +{ + int cm_protocol; + int cm_flags; + int cm_nassocs; + struct nl_sock * cm_handle; + struct nl_cache_assoc * cm_assocs; +}; + +struct nl_parser_param; + +#define LOOSE_COMPARISON 1 + +#define NL_OBJ_MARK 1 + +struct nl_data +{ + size_t d_size; + void * d_data; +}; + +struct nl_addr +{ + int a_family; + unsigned int a_maxsize; + unsigned int a_len; + int a_prefixlen; + int a_refcnt; + char a_addr[0]; +}; + +struct nl_msg +{ + int nm_protocol; + int nm_flags; + struct sockaddr_nl nm_src; + struct sockaddr_nl nm_dst; + struct ucred nm_creds; + struct nlmsghdr * nm_nlh; + size_t nm_size; + int nm_refcnt; +}; + +struct rtnl_link_map +{ + uint64_t lm_mem_start; + uint64_t lm_mem_end; + uint64_t lm_base_addr; + uint16_t lm_irq; + uint8_t lm_dma; + uint8_t lm_port; +}; + +#define IFQDISCSIZ 32 + +struct rtnl_link +{ + NLHDR_COMMON + + char l_name[IFNAMSIZ]; + uint32_t l_family; + uint32_t l_arptype; + uint32_t l_index; + uint32_t l_flags; + uint32_t l_change; + uint32_t l_mtu; + uint32_t l_link; + uint32_t l_txqlen; + uint32_t l_weight; + uint32_t l_master; + struct nl_addr * l_addr; + struct nl_addr * l_bcast; + char l_qdisc[IFQDISCSIZ]; + struct rtnl_link_map l_map; + uint64_t l_stats[RTNL_LINK_STATS_MAX+1]; + uint32_t l_flag_mask; + uint32_t l_num_vf; + uint8_t l_operstate; + uint8_t l_linkmode; + /* 2 byte hole */ + struct rtnl_link_info_ops * l_info_ops; + void * l_af_data[AF_MAX]; + void * l_info; + char * l_ifalias; +}; + +struct rtnl_ncacheinfo +{ + uint32_t nci_confirmed; /**< Time since neighbour validty was last confirmed */ + uint32_t nci_used; /**< Time since neighbour entry was last ued */ + uint32_t nci_updated; /**< Time since last update */ + uint32_t nci_refcnt; /**< Reference counter */ +}; + + +struct rtnl_neigh +{ + NLHDR_COMMON + uint32_t n_family; + uint32_t n_ifindex; + uint16_t n_state; + uint8_t n_flags; + uint8_t n_type; + struct nl_addr *n_lladdr; + struct nl_addr *n_dst; + uint32_t n_probes; + struct rtnl_ncacheinfo n_cacheinfo; + uint32_t n_state_mask; + uint32_t n_flag_mask; +}; + + +struct rtnl_addr_cacheinfo +{ + /* Preferred lifetime in seconds */ + uint32_t aci_prefered; + + /* Valid lifetime in seconds */ + uint32_t aci_valid; + + /* Timestamp of creation in 1/100s seince boottime */ + uint32_t aci_cstamp; + + /* Timestamp of last update in 1/100s since boottime */ + uint32_t aci_tstamp; +}; + +struct rtnl_addr +{ + NLHDR_COMMON + + uint8_t a_family; + uint8_t a_prefixlen; + uint8_t a_flags; + uint8_t a_scope; + uint32_t a_ifindex; + + struct nl_addr *a_peer; + struct nl_addr *a_local; + struct nl_addr *a_bcast; + struct nl_addr *a_anycast; + struct nl_addr *a_multicast; + + struct rtnl_addr_cacheinfo a_cacheinfo; + + char a_label[IFNAMSIZ]; + uint32_t a_flag_mask; + struct rtnl_link *a_link; +}; + +struct rtnl_nexthop +{ + uint8_t rtnh_flags; + uint8_t rtnh_flag_mask; + uint8_t rtnh_weight; + /* 1 byte spare */ + uint32_t rtnh_ifindex; + struct nl_addr * rtnh_gateway; + uint32_t ce_mask; /* HACK to support attr macros */ + struct nl_list_head rtnh_list; + uint32_t rtnh_realms; +}; + +struct rtnl_route +{ + NLHDR_COMMON + + uint8_t rt_family; + uint8_t rt_dst_len; + uint8_t rt_src_len; + uint8_t rt_tos; + uint8_t rt_protocol; + uint8_t rt_scope; + uint8_t rt_type; + uint8_t rt_nmetrics; + uint32_t rt_flags; + struct nl_addr * rt_dst; + struct nl_addr * rt_src; + uint32_t rt_table; + uint32_t rt_iif; + uint32_t rt_prio; + uint32_t rt_metrics[RTAX_MAX]; + uint32_t rt_metrics_mask; + uint32_t rt_nr_nh; + struct nl_addr * rt_pref_src; + struct nl_list_head rt_nexthops; + struct rtnl_rtcacheinfo rt_cacheinfo; + uint32_t rt_flag_mask; +}; + +struct rtnl_rule +{ + NLHDR_COMMON + uint8_t r_family; + uint8_t r_action; + uint8_t r_dsfield; /* ipv4 only */ + uint8_t r_unused; + uint32_t r_table; + uint32_t r_flags; + uint32_t r_prio; + uint32_t r_mark; + uint32_t r_mask; + uint32_t r_goto; + uint32_t r_flow; /* ipv4 only */ + struct nl_addr *r_src; + struct nl_addr *r_dst; + char r_iifname[IFNAMSIZ]; + char r_oifname[IFNAMSIZ]; +}; + +struct rtnl_neightbl_parms +{ + /** + * Interface index of the device this parameter set is assigned + * to or 0 for the default set. + */ + uint32_t ntp_ifindex; + + /** + * Number of references to this parameter set. + */ + uint32_t ntp_refcnt; + + /** + * Queue length for pending arp requests, i.e. the number of + * packets which are accepted from other layers while the + * neighbour address is still being resolved + */ + uint32_t ntp_queue_len; + + /** + * Number of requests to send to the user level ARP daemon. + * Specify 0 to disable. + */ + uint32_t ntp_app_probes; + + /** + * Maximum number of retries for unicast solicitation. + */ + uint32_t ntp_ucast_probes; + + /** + * Maximum number of retries for multicast solicitation. + */ + uint32_t ntp_mcast_probes; + + /** + * Base value in milliseconds to ompute reachable time, see RFC2461. + */ + uint64_t ntp_base_reachable_time; + + /** + * Actual reachable time (read-only) + */ + uint64_t ntp_reachable_time; /* secs */ + + /** + * The time in milliseconds between retransmitted Neighbor + * Solicitation messages. + */ + uint64_t ntp_retrans_time; + + /** + * Interval in milliseconds to check for stale neighbour + * entries. + */ + uint64_t ntp_gc_stale_time; /* secs */ + + /** + * Delay in milliseconds for the first time probe if + * the neighbour is reachable. + */ + uint64_t ntp_probe_delay; /* secs */ + + /** + * Maximum delay in milliseconds of an answer to a neighbour + * solicitation message. + */ + uint64_t ntp_anycast_delay; + + /** + * Minimum age in milliseconds before a neighbour entry + * may be replaced. + */ + uint64_t ntp_locktime; + + /** + * Delay in milliseconds before answering to an ARP request + * for which a proxy ARP entry exists. + */ + uint64_t ntp_proxy_delay; + + /** + * Queue length for the delayed proxy arp requests. + */ + uint32_t ntp_proxy_qlen; + + /** + * Mask of available parameter attributes + */ + uint32_t ntp_mask; +}; + +#define NTBLNAMSIZ 32 + +/** + * Neighbour table + * @ingroup neightbl + */ +struct rtnl_neightbl +{ + NLHDR_COMMON + + char nt_name[NTBLNAMSIZ]; + uint32_t nt_family; + uint32_t nt_gc_thresh1; + uint32_t nt_gc_thresh2; + uint32_t nt_gc_thresh3; + uint64_t nt_gc_interval; + struct ndt_config nt_config; + struct rtnl_neightbl_parms nt_parms; + struct ndt_stats nt_stats; +}; + +struct rtnl_ratespec +{ + uint8_t rs_cell_log; + uint16_t rs_overhead; + int16_t rs_cell_align; + uint16_t rs_mpu; + uint32_t rs_rate; +}; + +struct rtnl_tstats +{ + struct { + uint64_t bytes; + uint64_t packets; + } tcs_basic; + + struct { + uint32_t bps; + uint32_t pps; + } tcs_rate_est; + + struct { + uint32_t qlen; + uint32_t backlog; + uint32_t drops; + uint32_t requeues; + uint32_t overlimits; + } tcs_queue; +}; + +#define TCKINDSIZ 32 + +#define NL_TC_GENERIC(pre) \ + NLHDR_COMMON \ + uint32_t pre ##_family; \ + uint32_t pre ##_ifindex; \ + uint32_t pre ##_handle; \ + uint32_t pre ##_parent; \ + uint32_t pre ##_info; \ + uint32_t pre ##_mtu; \ + uint32_t pre ##_mpu; \ + uint32_t pre ##_overhead; \ + uint32_t pre ##_linktype; \ + char pre ##_kind[TCKINDSIZ]; \ + struct nl_data * pre ##_opts; \ + uint64_t pre ##_stats[RTNL_TC_STATS_MAX+1]; \ + struct nl_data * pre ##_xstats; \ + struct nl_data * pre ##_subdata; \ + struct rtnl_link * pre ##_link; \ + struct rtnl_tc_ops * pre ##_ops; \ + enum rtnl_tc_type pre ##_type + +struct rtnl_tc +{ + NL_TC_GENERIC(tc); +}; + +struct rtnl_qdisc +{ + NL_TC_GENERIC(q); +}; + +struct rtnl_class +{ + NL_TC_GENERIC(c); +}; + +struct rtnl_cls +{ + NL_TC_GENERIC(c); + uint16_t c_prio; + uint16_t c_protocol; +}; + +struct rtnl_u32 +{ + uint32_t cu_divisor; + uint32_t cu_hash; + uint32_t cu_classid; + uint32_t cu_link; + struct nl_data * cu_pcnt; + struct nl_data * cu_selector; + struct nl_data * cu_act; + struct nl_data * cu_police; + char cu_indev[IFNAMSIZ]; + int cu_mask; +}; + +struct rtnl_cgroup +{ + struct rtnl_ematch_tree *cg_ematch; + int cg_mask; +}; + +struct rtnl_fw +{ + uint32_t cf_classid; + struct nl_data * cf_act; + struct nl_data * cf_police; + char cf_indev[IFNAMSIZ]; + int cf_mask; +}; + +struct rtnl_ematch +{ + uint16_t e_id; + uint16_t e_kind; + uint16_t e_flags; + uint16_t e_index; + size_t e_datalen; + + struct nl_list_head e_childs; + struct nl_list_head e_list; + struct rtnl_ematch_ops *e_ops; + + void * e_data; +}; + +struct rtnl_ematch_tree +{ + uint16_t et_progid; + struct nl_list_head et_list; + +}; + +struct rtnl_dsmark_qdisc +{ + uint16_t qdm_indices; + uint16_t qdm_default_index; + uint32_t qdm_set_tc_index; + uint32_t qdm_mask; +}; + +struct rtnl_dsmark_class +{ + uint8_t cdm_bmask; + uint8_t cdm_value; + uint32_t cdm_mask; +}; + +struct rtnl_fifo +{ + uint32_t qf_limit; + uint32_t qf_mask; +}; + +struct rtnl_prio +{ + uint32_t qp_bands; + uint8_t qp_priomap[TC_PRIO_MAX+1]; + uint32_t qp_mask; +}; + +struct rtnl_tbf +{ + uint32_t qt_limit; + struct rtnl_ratespec qt_rate; + uint32_t qt_rate_bucket; + uint32_t qt_rate_txtime; + struct rtnl_ratespec qt_peakrate; + uint32_t qt_peakrate_bucket; + uint32_t qt_peakrate_txtime; + uint32_t qt_mask; +}; + +struct rtnl_sfq +{ + uint32_t qs_quantum; + uint32_t qs_perturb; + uint32_t qs_limit; + uint32_t qs_divisor; + uint32_t qs_flows; + uint32_t qs_mask; +}; + +struct rtnl_netem_corr +{ + uint32_t nmc_delay; + uint32_t nmc_loss; + uint32_t nmc_duplicate; +}; + +struct rtnl_netem_reo +{ + uint32_t nmro_probability; + uint32_t nmro_correlation; +}; + +struct rtnl_netem_crpt +{ + uint32_t nmcr_probability; + uint32_t nmcr_correlation; +}; + +struct rtnl_netem_dist +{ + int16_t * dist_data; + size_t dist_size; +}; + +struct rtnl_netem +{ + uint32_t qnm_latency; + uint32_t qnm_limit; + uint32_t qnm_loss; + uint32_t qnm_gap; + uint32_t qnm_duplicate; + uint32_t qnm_jitter; + uint32_t qnm_mask; + struct rtnl_netem_corr qnm_corr; + struct rtnl_netem_reo qnm_ro; + struct rtnl_netem_crpt qnm_crpt; + struct rtnl_netem_dist qnm_dist; +}; + +struct rtnl_htb_qdisc +{ + uint32_t qh_rate2quantum; + uint32_t qh_defcls; + uint32_t qh_mask; + uint32_t qh_direct_pkts; +}; + +struct rtnl_htb_class +{ + uint32_t ch_prio; + struct rtnl_ratespec ch_rate; + struct rtnl_ratespec ch_ceil; + uint32_t ch_rbuffer; + uint32_t ch_cbuffer; + uint32_t ch_quantum; + uint32_t ch_mask; + uint32_t ch_level; +}; + +struct rtnl_cbq +{ + struct tc_cbq_lssopt cbq_lss; + struct tc_ratespec cbq_rate; + struct tc_cbq_wrropt cbq_wrr; + struct tc_cbq_ovl cbq_ovl; + struct tc_cbq_fopt cbq_fopt; + struct tc_cbq_police cbq_police; +}; + +struct rtnl_red +{ + uint32_t qr_limit; + uint32_t qr_qth_min; + uint32_t qr_qth_max; + uint8_t qr_flags; + uint8_t qr_wlog; + uint8_t qr_plog; + uint8_t qr_scell_log; + uint32_t qr_mask; +}; + +struct flnl_request +{ + NLHDR_COMMON + + struct nl_addr * lr_addr; + uint32_t lr_fwmark; + uint8_t lr_tos; + uint8_t lr_scope; + uint8_t lr_table; +}; + + +struct flnl_result +{ + NLHDR_COMMON + + struct flnl_request * fr_req; + uint8_t fr_table_id; + uint8_t fr_prefixlen; + uint8_t fr_nh_sel; + uint8_t fr_type; + uint8_t fr_scope; + uint32_t fr_error; +}; + +#define GENL_OP_HAS_POLICY 1 +#define GENL_OP_HAS_DOIT 2 +#define GENL_OP_HAS_DUMPIT 4 + +struct genl_family_op +{ + uint32_t o_id; + uint32_t o_flags; + + struct nl_list_head o_list; +}; + +struct genl_family_grp { + struct genl_family *family; /* private */ + struct nl_list_head list; /* private */ + char name[GENL_NAMSIZ]; + u_int32_t id; +}; + +struct genl_family +{ + NLHDR_COMMON + + uint16_t gf_id; + char gf_name[GENL_NAMSIZ]; + uint32_t gf_version; + uint32_t gf_hdrsize; + uint32_t gf_maxattr; + + struct nl_list_head gf_ops; + struct nl_list_head gf_mc_grps; +}; + +union nfnl_ct_proto +{ + struct { + uint16_t src; + uint16_t dst; + } port; + struct { + uint16_t id; + uint8_t type; + uint8_t code; + } icmp; +}; + +struct nfnl_ct_dir { + struct nl_addr * src; + struct nl_addr * dst; + union nfnl_ct_proto proto; + uint64_t packets; + uint64_t bytes; +}; + +union nfnl_ct_protoinfo { + struct { + uint8_t state; + } tcp; +}; + +struct nfnl_ct { + NLHDR_COMMON + + uint8_t ct_family; + uint8_t ct_proto; + union nfnl_ct_protoinfo ct_protoinfo; + + uint32_t ct_status; + uint32_t ct_status_mask; + uint32_t ct_timeout; + uint32_t ct_mark; + uint32_t ct_use; + uint32_t ct_id; + + struct nfnl_ct_dir ct_orig; + struct nfnl_ct_dir ct_repl; +}; + +struct nfnl_log { + NLHDR_COMMON + + uint16_t log_group; + uint8_t log_copy_mode; + uint32_t log_copy_range; + uint32_t log_flush_timeout; + uint32_t log_alloc_size; + uint32_t log_queue_threshold; + uint32_t log_flags; + uint32_t log_flag_mask; +}; + +struct nfnl_log_msg { + NLHDR_COMMON + + uint8_t log_msg_family; + uint8_t log_msg_hook; + uint16_t log_msg_hwproto; + uint32_t log_msg_mark; + struct timeval log_msg_timestamp; + uint32_t log_msg_indev; + uint32_t log_msg_outdev; + uint32_t log_msg_physindev; + uint32_t log_msg_physoutdev; + uint8_t log_msg_hwaddr[8]; + int log_msg_hwaddr_len; + void * log_msg_payload; + int log_msg_payload_len; + char * log_msg_prefix; + uint32_t log_msg_uid; + uint32_t log_msg_gid; + uint32_t log_msg_seq; + uint32_t log_msg_seq_global; +}; + +struct nfnl_queue { + NLHDR_COMMON + + uint16_t queue_group; + uint32_t queue_maxlen; + uint32_t queue_copy_range; + uint8_t queue_copy_mode; +}; + +struct nfnl_queue_msg { + NLHDR_COMMON + + uint16_t queue_msg_group; + uint8_t queue_msg_family; + uint8_t queue_msg_hook; + uint16_t queue_msg_hwproto; + uint32_t queue_msg_packetid; + uint32_t queue_msg_mark; + struct timeval queue_msg_timestamp; + uint32_t queue_msg_indev; + uint32_t queue_msg_outdev; + uint32_t queue_msg_physindev; + uint32_t queue_msg_physoutdev; + uint8_t queue_msg_hwaddr[8]; + int queue_msg_hwaddr_len; + void * queue_msg_payload; + int queue_msg_payload_len; + uint32_t queue_msg_verdict; +}; + +struct ematch_quoted { + char * data; + size_t len; + int index; +}; + +#endif diff --git a/libnetwork/libnl3/include/netlink/addr.h b/libnetwork/libnl3/include/netlink/addr.h new file mode 100644 index 0000000..794c4ff --- /dev/null +++ b/libnetwork/libnl3/include/netlink/addr.h @@ -0,0 +1,66 @@ +/* + * netlink/addr.h Abstract Address + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2010 Thomas Graf + */ + +#ifndef NETLINK_ADDR_H_ +#define NETLINK_ADDR_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct nl_addr; + +/* Creation */ +extern struct nl_addr * nl_addr_alloc(size_t); +extern struct nl_addr * nl_addr_alloc_attr(struct nlattr *, int); +extern struct nl_addr * nl_addr_build(int, void *, size_t); +extern int nl_addr_parse(const char *, int, struct nl_addr **); +extern struct nl_addr * nl_addr_clone(struct nl_addr *); + +/* Usage Management */ +extern struct nl_addr * nl_addr_get(struct nl_addr *); +extern void nl_addr_put(struct nl_addr *); +extern int nl_addr_shared(struct nl_addr *); + +extern int nl_addr_cmp(struct nl_addr *, struct nl_addr *); +extern int nl_addr_cmp_prefix(struct nl_addr *, struct nl_addr *); +extern int nl_addr_iszero(struct nl_addr *); +extern int nl_addr_valid(char *, int); +extern int nl_addr_guess_family(struct nl_addr *); +extern int nl_addr_fill_sockaddr(struct nl_addr *, + struct sockaddr *, socklen_t *); +extern int nl_addr_info(struct nl_addr *, struct addrinfo **); +extern int nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen); + +/* Access Functions */ +extern void nl_addr_set_family(struct nl_addr *, int); +extern int nl_addr_get_family(struct nl_addr *); +extern int nl_addr_set_binary_addr(struct nl_addr *, void *, + size_t); +extern void * nl_addr_get_binary_addr(struct nl_addr *); +extern unsigned int nl_addr_get_len(struct nl_addr *); +extern void nl_addr_set_prefixlen(struct nl_addr *, int); +extern unsigned int nl_addr_get_prefixlen(struct nl_addr *); + +/* Address Family Translations */ +extern char * nl_af2str(int, char *, size_t); +extern int nl_str2af(const char *); + +/* Translations to Strings */ +extern char * nl_addr2str(struct nl_addr *, char *, size_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/attr.h b/libnetwork/libnl3/include/netlink/attr.h new file mode 100644 index 0000000..8479c23 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/attr.h @@ -0,0 +1,283 @@ +/* + * netlink/attr.h Netlink Attributes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_ATTR_H_ +#define NETLINK_ATTR_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct nl_msg; + +/** + * @name Basic Attribute Data Types + * @{ + */ + + /** + * @ingroup attr + * Basic attribute data types + * + * See \ref attr_datatypes for more details. + */ +enum { + NLA_UNSPEC, /**< Unspecified type, binary data chunk */ + NLA_U8, /**< 8 bit integer */ + NLA_U16, /**< 16 bit integer */ + NLA_U32, /**< 32 bit integer */ + NLA_U64, /**< 64 bit integer */ + NLA_STRING, /**< NUL terminated character string */ + NLA_FLAG, /**< Flag */ + NLA_MSECS, /**< Micro seconds (64bit) */ + NLA_NESTED, /**< Nested attributes */ + __NLA_TYPE_MAX, +}; + +#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1) + +/** @} */ + +/** + * @ingroup attr + * Attribute validation policy. + * + * See \ref attr_datatypes for more details. + */ +struct nla_policy { + /** Type of attribute or NLA_UNSPEC */ + uint16_t type; + + /** Minimal length of payload required */ + uint16_t minlen; + + /** Maximal length of payload allowed */ + uint16_t maxlen; +}; + +/* Size calculations */ +extern int nla_attr_size(int payload); +extern int nla_total_size(int payload); +extern int nla_padlen(int payload); + +/* Attribute parsing */ +extern int nla_type(const struct nlattr *); +extern void * nla_data(const struct nlattr *); +extern int nla_len(const struct nlattr *); +extern int nla_ok(const struct nlattr *, int); +extern struct nlattr * nla_next(const struct nlattr *, int *); +extern int nla_parse(struct nlattr **, int, struct nlattr *, + int, struct nla_policy *); +extern int nla_validate(struct nlattr *, int, int, + struct nla_policy *); +extern struct nlattr * nla_find(struct nlattr *, int, int); + +/* Helper Functions */ +extern int nla_memcpy(void *, struct nlattr *, int); +extern size_t nla_strlcpy(char *, const struct nlattr *, size_t); +extern int nla_memcmp(const struct nlattr *, const void *, size_t); +extern int nla_strcmp(const struct nlattr *, const char *); + +/* Unspecific attribute */ +extern struct nlattr * nla_reserve(struct nl_msg *, int, int); +extern int nla_put(struct nl_msg *, int, int, const void *); +extern int nla_put_data(struct nl_msg *, int, struct nl_data *); +extern int nla_put_addr(struct nl_msg *, int, struct nl_addr *); + +/* Integer attribute */ +extern uint8_t nla_get_u8(struct nlattr *); +extern int nla_put_u8(struct nl_msg *, int, uint8_t); +extern uint16_t nla_get_u16(struct nlattr *); +extern int nla_put_u16(struct nl_msg *, int, uint16_t); +extern uint32_t nla_get_u32(struct nlattr *); +extern int nla_put_u32(struct nl_msg *, int, uint32_t); +extern uint64_t nla_get_u64(struct nlattr *); +extern int nla_put_u64(struct nl_msg *, int, uint64_t); + +/* String attribute */ +extern char * nla_get_string(struct nlattr *); +extern char * nla_strdup(struct nlattr *); +extern int nla_put_string(struct nl_msg *, int, const char *); + +/* Flag attribute */ +extern int nla_get_flag(struct nlattr *); +extern int nla_put_flag(struct nl_msg *, int); + +/* Msec attribute */ +extern unsigned long nla_get_msecs(struct nlattr *); +extern int nla_put_msecs(struct nl_msg *, int, unsigned long); + +/* Attribute nesting */ +extern int nla_put_nested(struct nl_msg *, int, struct nl_msg *); +extern struct nlattr * nla_nest_start(struct nl_msg *, int); +extern int nla_nest_end(struct nl_msg *, struct nlattr *); +extern int nla_parse_nested(struct nlattr **, int, struct nlattr *, + struct nla_policy *); + +/** + * @name Attribute Construction (Exception Based) + * @{ + */ + +/** + * @ingroup attr + * Add unspecific attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg attrlen Length of attribute payload. + * @arg data Head of attribute payload. + */ +#define NLA_PUT(msg, attrtype, attrlen, data) \ + do { \ + if (nla_put(msg, attrtype, attrlen, data) < 0) \ + goto nla_put_failure; \ + } while(0) + +/** + * @ingroup attr + * Add atomic type attribute to netlink message. + * @arg msg Netlink message. + * @arg type Atomic type. + * @arg attrtype Attribute type. + * @arg value Head of attribute payload. + */ +#define NLA_PUT_TYPE(msg, type, attrtype, value) \ + do { \ + type __tmp = value; \ + NLA_PUT(msg, attrtype, sizeof(type), &__tmp); \ + } while(0) + +/** + * Add 8 bit integer attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value Numeric value. + */ +#define NLA_PUT_U8(msg, attrtype, value) \ + NLA_PUT_TYPE(msg, uint8_t, attrtype, value) + +/** + * Add 16 bit integer attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value Numeric value. + */ +#define NLA_PUT_U16(msg, attrtype, value) \ + NLA_PUT_TYPE(msg, uint16_t, attrtype, value) + +/** + * Add 32 bit integer attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value Numeric value. + */ +#define NLA_PUT_U32(msg, attrtype, value) \ + NLA_PUT_TYPE(msg, uint32_t, attrtype, value) + +/** + * Add 64 bit integer attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value Numeric value. + */ +#define NLA_PUT_U64(msg, attrtype, value) \ + NLA_PUT_TYPE(msg, uint64_t, attrtype, value) + +/** + * Add string attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value NUL terminated character string. + */ +#define NLA_PUT_STRING(msg, attrtype, value) \ + NLA_PUT(msg, attrtype, strlen(value) + 1, value) + +/** + * Add flag attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + */ +#define NLA_PUT_FLAG(msg, attrtype) \ + NLA_PUT(msg, attrtype, 0, NULL) + +/** + * Add msecs attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg msecs Numeric value in micro seconds. + */ +#define NLA_PUT_MSECS(msg, attrtype, msecs) \ + NLA_PUT_U64(msg, attrtype, msecs) + +/** + * Add address attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg addr Abstract address object. + */ +#define NLA_PUT_ADDR(msg, attrtype, addr) \ + NLA_PUT(msg, attrtype, nl_addr_get_len(addr), \ + nl_addr_get_binary_addr(addr)) + +/** + * Add abstract data attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg data Abstract data object. + */ +#define NLA_PUT_DATA(msg, attrtype, data) \ + NLA_PUT(msg, attrtype, nl_data_get_size(data), \ + nl_data_get(data)) + +/** @} */ + +/** + * @name Iterators + * @{ + */ + +/** + * @ingroup attr + * Iterate over a stream of attributes + * @arg pos loop counter, set to current attribute + * @arg head head of attribute stream + * @arg len length of attribute stream + * @arg rem initialized to len, holds bytes currently remaining in stream + */ +#define nla_for_each_attr(pos, head, len, rem) \ + for (pos = head, rem = len; \ + nla_ok(pos, rem); \ + pos = nla_next(pos, &(rem))) + +/** + * @ingroup attr + * Iterate over a stream of nested attributes + * @arg pos loop counter, set to current attribute + * @arg nla attribute containing the nested attributes + * @arg rem initialized to len, holds bytes currently remaining in stream + */ +#define nla_for_each_nested(pos, nla, rem) \ + for (pos = nla_data(nla), rem = nla_len(nla); \ + nla_ok(pos, rem); \ + pos = nla_next(pos, &(rem))) + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/cache-api.h b/libnetwork/libnl3/include/netlink/cache-api.h new file mode 100644 index 0000000..1b3d099 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/cache-api.h @@ -0,0 +1,230 @@ +/* + * netlink/cache-api.h Caching API + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_CACHE_API_H_ +#define NETLINK_CACHE_API_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @ingroup cache + * @defgroup cache_api Cache Implementation + * @brief + * + * @par 1) Cache Definition + * @code + * struct nl_cache_ops my_cache_ops = { + * .co_name = "route/link", + * .co_protocol = NETLINK_ROUTE, + * .co_hdrsize = sizeof(struct ifinfomsg), + * .co_obj_ops = &my_obj_ops, + * }; + * @endcode + * + * @par 2) + * @code + * // The simplest way to fill a cache is by providing a request-update + * // function which must trigger a complete dump on the kernel-side of + * // whatever the cache covers. + * static int my_request_update(struct nl_cache *cache, + * struct nl_sock *socket) + * { + * // In this example, we request a full dump of the interface table + * return nl_rtgen_request(socket, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP); + * } + * + * // The resulting netlink messages sent back will be fed into a message + * // parser one at a time. The message parser has to extract all relevant + * // information from the message and create an object reflecting the + * // contents of the message and pass it on to the parser callback function + * // provide which will add the object to the cache. + * static int my_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + * struct nlmsghdr *nlh, struct nl_parser_param *pp) + * { + * struct my_obj *obj; + * + * obj = my_obj_alloc(); + * obj->ce_msgtype = nlh->nlmsg_type; + * + * // Parse the netlink message and continue creating the object. + * + * err = pp->pp_cb((struct nl_object *) obj, pp); + * if (err < 0) + * goto errout; + * } + * + * struct nl_cache_ops my_cache_ops = { + * ... + * .co_request_update = my_request_update, + * .co_msg_parser = my_msg_parser, + * }; + * @endcode + * + * @par 3) Notification based Updates + * @code + * // Caches can be kept up-to-date based on notifications if the kernel + * // sends out notifications whenever an object is added/removed/changed. + * // + * // It is trivial to support this, first a list of groups needs to be + * // defined which are required to join in order to receive all necessary + * // notifications. The groups are separated by address family to support + * // the common situation where a separate group is used for each address + * // family. If there is only one group, simply specify AF_UNSPEC. + * static struct nl_af_group addr_groups[] = { + * { AF_INET, RTNLGRP_IPV4_IFADDR }, + * { AF_INET6, RTNLGRP_IPV6_IFADDR }, + * { END_OF_GROUP_LIST }, + * }; + * + * // In order for the caching system to know the meaning of each message + * // type it requires a table which maps each supported message type to + * // a cache action, e.g. RTM_NEWADDR means address has been added or + * // updated, RTM_DELADDR means address has been removed. + * static struct nl_cache_ops rtnl_addr_ops = { + * ... + * .co_msgtypes = { + * { RTM_NEWADDR, NL_ACT_NEW, "new" }, + * { RTM_DELADDR, NL_ACT_DEL, "del" }, + * { RTM_GETADDR, NL_ACT_GET, "get" }, + * END_OF_MSGTYPES_LIST, + * }, + * .co_groups = addr_groups, + * }; + * + * // It is now possible to keep the cache up-to-date using the cache manager. + * @endcode + * @{ + */ + +enum { + NL_ACT_UNSPEC, + NL_ACT_NEW, + NL_ACT_DEL, + NL_ACT_GET, + NL_ACT_SET, + NL_ACT_CHANGE, + __NL_ACT_MAX, +}; + +#define NL_ACT_MAX (__NL_ACT_MAX - 1) + +#define END_OF_MSGTYPES_LIST { -1, -1, NULL } + +/** + * Message type to cache action association + */ +struct nl_msgtype +{ + /** Netlink message type */ + int mt_id; + + /** Cache action to take */ + int mt_act; + + /** Name of operation for human-readable printing */ + char * mt_name; +}; + +/** + * Address family to netlink group association + */ +struct nl_af_group +{ + /** Address family */ + int ag_family; + + /** Netlink group identifier */ + int ag_group; +}; + +#define END_OF_GROUP_LIST AF_UNSPEC, 0 + +/** + * Parser parameters + * + * This structure is used to configure what kind of parser to use + * when parsing netlink messages to create objects. + */ +struct nl_parser_param +{ + /** Function to parse netlink messages into objects */ + int (*pp_cb)(struct nl_object *, struct nl_parser_param *); + + /** Arbitary argument to be passed to the parser */ + void * pp_arg; +}; + +/** + * Cache Operations + * + * This structure defines the characterstics of a cache type. It contains + * pointers to functions which implement the specifics of the object type + * the cache can hold. + */ +struct nl_cache_ops +{ + /** Name of cache type (must be unique) */ + char * co_name; + + /** Size of family specific netlink header */ + int co_hdrsize; + + /** Netlink protocol */ + int co_protocol; + + /** Group definition */ + struct nl_af_group * co_groups; + + /** + * Called whenever an update of the cache is required. Must send + * a request message to the kernel requesting a complete dump. + */ + int (*co_request_update)(struct nl_cache *, struct nl_sock *); + + /** + * Called whenever a message was received that needs to be parsed. + * Must parse the message and call the paser callback function + * (nl_parser_param) provided via the argument. + */ + int (*co_msg_parser)(struct nl_cache_ops *, struct sockaddr_nl *, + struct nlmsghdr *, struct nl_parser_param *); + + /** + * Called whenever a notification has been parsed into an object and + * is considered for inclusion into a cache. Must return NL_SKIP if + * the object should not be included in the cache. + */ + int (*co_event_filter)(struct nl_cache *, struct nl_object *obj); + + /** Object operations */ + struct nl_object_ops * co_obj_ops; + + /** Internal, do not touch! */ + struct nl_cache_ops *co_next; + + struct nl_cache *co_major_cache; + struct genl_ops * co_genl; + + /* Message type definition */ + struct nl_msgtype co_msgtypes[]; +}; + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/cache.h b/libnetwork/libnl3/include/netlink/cache.h new file mode 100644 index 0000000..f8073f0 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/cache.h @@ -0,0 +1,134 @@ +/* + * netlink/cache.h Caching Module + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_CACHE_H_ +#define NETLINK_CACHE_H_ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct nl_cache; + +typedef void (*change_func_t)(struct nl_cache *, struct nl_object *, int, void *); + +/* Access Functions */ +extern int nl_cache_nitems(struct nl_cache *); +extern int nl_cache_nitems_filter(struct nl_cache *, + struct nl_object *); +extern struct nl_cache_ops * nl_cache_get_ops(struct nl_cache *); +extern struct nl_object * nl_cache_get_first(struct nl_cache *); +extern struct nl_object * nl_cache_get_last(struct nl_cache *); +extern struct nl_object * nl_cache_get_next(struct nl_object *); +extern struct nl_object * nl_cache_get_prev(struct nl_object *); + +extern struct nl_cache * nl_cache_alloc(struct nl_cache_ops *); +extern int nl_cache_alloc_and_fill(struct nl_cache_ops *, + struct nl_sock *, + struct nl_cache **); +extern int nl_cache_alloc_name(const char *, + struct nl_cache **); +extern struct nl_cache * nl_cache_subset(struct nl_cache *, + struct nl_object *); +extern void nl_cache_clear(struct nl_cache *); +extern void nl_cache_free(struct nl_cache *); + +/* Cache modification */ +extern int nl_cache_add(struct nl_cache *, + struct nl_object *); +extern int nl_cache_parse_and_add(struct nl_cache *, + struct nl_msg *); +extern void nl_cache_remove(struct nl_object *); +extern int nl_cache_refill(struct nl_sock *, + struct nl_cache *); +extern int nl_cache_pickup(struct nl_sock *, + struct nl_cache *); +extern int nl_cache_resync(struct nl_sock *, + struct nl_cache *, + change_func_t, + void *); +extern int nl_cache_include(struct nl_cache *, + struct nl_object *, + change_func_t, + void *); +extern void nl_cache_set_arg1(struct nl_cache *, int); +extern void nl_cache_set_arg2(struct nl_cache *, int); + +/* General */ +extern int nl_cache_is_empty(struct nl_cache *); +extern struct nl_object * nl_cache_search(struct nl_cache *, + struct nl_object *); +extern void nl_cache_mark_all(struct nl_cache *); + +/* Dumping */ +extern void nl_cache_dump(struct nl_cache *, + struct nl_dump_params *); +extern void nl_cache_dump_filter(struct nl_cache *, + struct nl_dump_params *, + struct nl_object *); + +/* Iterators */ +extern void nl_cache_foreach(struct nl_cache *, + void (*cb)(struct nl_object *, + void *), + void *arg); +extern void nl_cache_foreach_filter(struct nl_cache *, + struct nl_object *, + void (*cb)(struct + nl_object *, + void *), + void *arg); + +/* --- cache management --- */ + +/* Cache type management */ +extern struct nl_cache_ops * nl_cache_ops_lookup(const char *); +extern struct nl_cache_ops * nl_cache_ops_associate(int, int); +extern struct nl_msgtype * nl_msgtype_lookup(struct nl_cache_ops *, int); +extern void nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *); +extern int nl_cache_mngt_register(struct nl_cache_ops *); +extern int nl_cache_mngt_unregister(struct nl_cache_ops *); + +/* Global cache provisioning/requiring */ +extern void nl_cache_mngt_provide(struct nl_cache *); +extern void nl_cache_mngt_unprovide(struct nl_cache *); +extern struct nl_cache * nl_cache_mngt_require(const char *); +extern struct nl_cache * __nl_cache_mngt_require(const char *); + +struct nl_cache_mngr; + +#define NL_AUTO_PROVIDE 1 + +extern int nl_cache_mngr_alloc(struct nl_sock *, + int, int, + struct nl_cache_mngr **); +extern int nl_cache_mngr_add(struct nl_cache_mngr *, + const char *, + change_func_t, + void *, + struct nl_cache **); +extern int nl_cache_mngr_get_fd(struct nl_cache_mngr *); +extern int nl_cache_mngr_poll(struct nl_cache_mngr *, + int); +extern int nl_cache_mngr_data_ready(struct nl_cache_mngr *); +extern void nl_cache_mngr_free(struct nl_cache_mngr *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/cli/addr.h b/libnetwork/libnl3/include/netlink/cli/addr.h new file mode 100644 index 0000000..d0fd055 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/cli/addr.h @@ -0,0 +1,32 @@ +/* + * netlink/cli/addr.h CLI Address Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf + */ + +#ifndef __NETLINK_CLI_ADDR_H_ +#define __NETLINK_CLI_ADDR_H_ + +#include + +#define nl_cli_addr_alloc_cache(sk) \ + nl_cli_alloc_cache((sk), "address", rtnl_addr_alloc_cache) + +extern struct rtnl_addr *nl_cli_addr_alloc(void); + +extern void nl_cli_addr_parse_family(struct rtnl_addr *, char *); +extern void nl_cli_addr_parse_local(struct rtnl_addr *, char *); +extern void nl_cli_addr_parse_dev(struct rtnl_addr *, struct nl_cache *,char *); +extern void nl_cli_addr_parse_label(struct rtnl_addr *, char *); +extern void nl_cli_addr_parse_peer(struct rtnl_addr *, char *); +extern void nl_cli_addr_parse_scope(struct rtnl_addr *, char *); +extern void nl_cli_addr_parse_broadcast(struct rtnl_addr *, char *); +extern void nl_cli_addr_parse_preferred(struct rtnl_addr *, char *); +extern void nl_cli_addr_parse_valid(struct rtnl_addr *, char *); + +#endif diff --git a/libnetwork/libnl3/include/netlink/cli/class.h b/libnetwork/libnl3/include/netlink/cli/class.h new file mode 100644 index 0000000..5001e42 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/cli/class.h @@ -0,0 +1,21 @@ +/* + * netlink/cli/class.h CLI Class Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf + */ + +#ifndef __NETLINK_CLI_CLASS_H_ +#define __NETLINK_CLI_CLASS_H_ + +#include +#include + +extern struct rtnl_class *nl_cli_class_alloc(void); +extern struct nl_cache *nl_cli_class_alloc_cache(struct nl_sock *, int); + +#endif diff --git a/libnetwork/libnl3/include/netlink/cli/cls.h b/libnetwork/libnl3/include/netlink/cli/cls.h new file mode 100644 index 0000000..a2707b8 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/cli/cls.h @@ -0,0 +1,24 @@ +/* + * netlink/cli/cls.h CLI Classifier Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf + */ + +#ifndef __NETLINK_CLI_CLS_H_ +#define __NETLINK_CLI_CLS_H_ + +#include +#include + +extern struct rtnl_cls * nl_cli_cls_alloc(void); +extern struct nl_cache * nl_cli_cls_alloc_cache(struct nl_sock *, + int, uint32_t); +extern void nl_cli_cls_parse_proto(struct rtnl_cls *, char *); +extern struct rtnl_ematch_tree *nl_cli_cls_parse_ematch(struct rtnl_cls *, char *); + +#endif diff --git a/libnetwork/libnl3/include/netlink/cli/ct.h b/libnetwork/libnl3/include/netlink/cli/ct.h new file mode 100644 index 0000000..bed776b --- /dev/null +++ b/libnetwork/libnl3/include/netlink/cli/ct.h @@ -0,0 +1,34 @@ +/* + * netlink/cli/ct.h CLI Conntrack Helper + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf + */ + +#ifndef __NETLINK_CLI_CT_H_ +#define __NETLINK_CLI_CT_H_ + +#include +#include + +extern struct nfnl_ct *nl_cli_ct_alloc(void); +extern struct nl_cache *nl_cli_ct_alloc_cache(struct nl_sock *); + +extern void nl_cli_ct_parse_family(struct nfnl_ct *, char *); +extern void nl_cli_ct_parse_protocol(struct nfnl_ct *, char *); +extern void nl_cli_ct_parse_mark(struct nfnl_ct *, char *); +extern void nl_cli_ct_parse_timeout(struct nfnl_ct *, char *); +extern void nl_cli_ct_parse_id(struct nfnl_ct *, char *); +extern void nl_cli_ct_parse_use(struct nfnl_ct *, char *); +extern void nl_cli_ct_parse_src(struct nfnl_ct *, int, char *); +extern void nl_cli_ct_parse_dst(struct nfnl_ct *, int, char *); +extern void nl_cli_ct_parse_src_port(struct nfnl_ct *, int, char *); +extern void nl_cli_ct_parse_dst_port(struct nfnl_ct *, int, char *); +extern void nl_cli_ct_parse_tcp_state(struct nfnl_ct *, char *); +extern void nl_cli_ct_parse_status(struct nfnl_ct *, char *); + +#endif diff --git a/libnetwork/libnl3/include/netlink/cli/link.h b/libnetwork/libnl3/include/netlink/cli/link.h new file mode 100644 index 0000000..3f37948 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/cli/link.h @@ -0,0 +1,30 @@ +/* + * netlink/cli/link.h CLI Link Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2010 Thomas Graf + */ + +#ifndef __NETLINK_CLI_LINK_H_ +#define __NETLINK_CLI_LINK_H_ + +#include +#include + +extern struct rtnl_link *nl_cli_link_alloc(void); +extern struct nl_cache *nl_cli_link_alloc_cache_family(struct nl_sock *, int); +extern struct nl_cache *nl_cli_link_alloc_cache(struct nl_sock *); + +extern void nl_cli_link_parse_family(struct rtnl_link *, char *); +extern void nl_cli_link_parse_name(struct rtnl_link *, char *); +extern void nl_cli_link_parse_mtu(struct rtnl_link *, char *); +extern void nl_cli_link_parse_ifindex(struct rtnl_link *, char *); +extern void nl_cli_link_parse_txqlen(struct rtnl_link *, char *); +extern void nl_cli_link_parse_weight(struct rtnl_link *, char *); +extern void nl_cli_link_parse_ifalias(struct rtnl_link *, char *); + +#endif diff --git a/libnetwork/libnl3/include/netlink/cli/neigh.h b/libnetwork/libnl3/include/netlink/cli/neigh.h new file mode 100644 index 0000000..5440012 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/cli/neigh.h @@ -0,0 +1,27 @@ +/* + * netlink/cli/neighbour.h CLI Neighbour Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf + */ + +#ifndef __NETLINK_CLI_NEIGH_H_ +#define __NETLINK_CLI_NEIGH_H_ + +#include + +#define nl_cli_neigh_alloc_cache(sk) \ + nl_cli_alloc_cache((sk), "neighbour", rtnl_neigh_alloc_cache) + +extern struct rtnl_neigh *nl_cli_neigh_alloc(void); +extern void nl_cli_neigh_parse_dst(struct rtnl_neigh *, char *); +extern void nl_cli_neigh_parse_lladdr(struct rtnl_neigh *, char *); +extern void nl_cli_neigh_parse_dev(struct rtnl_neigh *, struct nl_cache *, char *); +extern void nl_cli_neigh_parse_family(struct rtnl_neigh *, char *); +extern void nl_cli_neigh_parse_state(struct rtnl_neigh *, char *); + +#endif diff --git a/libnetwork/libnl3/include/netlink/cli/qdisc.h b/libnetwork/libnl3/include/netlink/cli/qdisc.h new file mode 100644 index 0000000..b102da4 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/cli/qdisc.h @@ -0,0 +1,23 @@ +/* + * netlink/cli/qdisc.h CLI QDisc Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2011 Thomas Graf + */ + +#ifndef __NETLINK_CLI_QDISC_H_ +#define __NETLINK_CLI_QDISC_H_ + +#include + +#define nl_cli_qdisc_alloc_cache(sk) \ + nl_cli_alloc_cache((sk), "queueing disciplines", \ + rtnl_qdisc_alloc_cache) + +extern struct rtnl_qdisc *nl_cli_qdisc_alloc(void); + +#endif diff --git a/libnetwork/libnl3/include/netlink/cli/route.h b/libnetwork/libnl3/include/netlink/cli/route.h new file mode 100644 index 0000000..089c658 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/cli/route.h @@ -0,0 +1,34 @@ +/* + * netlink/cli//route.h CLI Route Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf + */ + +#ifndef __NETLINK_CLI_ROUTE_H_ +#define __NETLINK_CLI_ROUTE_H_ + +#include + +extern struct rtnl_route *nl_cli_route_alloc(void); + +extern struct nl_cache *nl_cli_route_alloc_cache(struct nl_sock *, int); + +extern void nl_cli_route_parse_family(struct rtnl_route *, char *); +extern void nl_cli_route_parse_dst(struct rtnl_route *, char *); +extern void nl_cli_route_parse_src(struct rtnl_route *, char *); +extern void nl_cli_route_parse_pref_src(struct rtnl_route *, char *); +extern void nl_cli_route_parse_metric(struct rtnl_route *, char *); +extern void nl_cli_route_parse_nexthop(struct rtnl_route *, char *, struct nl_cache *); +extern void nl_cli_route_parse_table(struct rtnl_route *, char *); +extern void nl_cli_route_parse_prio(struct rtnl_route *, char *); +extern void nl_cli_route_parse_scope(struct rtnl_route *, char *); +extern void nl_cli_route_parse_protocol(struct rtnl_route *, char *); +extern void nl_cli_route_parse_type(struct rtnl_route *, char *); +extern void nl_cli_route_parse_iif(struct rtnl_route *, char *, struct nl_cache *); + +#endif diff --git a/libnetwork/libnl3/include/netlink/cli/rule.h b/libnetwork/libnl3/include/netlink/cli/rule.h new file mode 100644 index 0000000..61cd63e --- /dev/null +++ b/libnetwork/libnl3/include/netlink/cli/rule.h @@ -0,0 +1,21 @@ +/* + * netlink/cli/rule.h CLI Routing Rule Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf + */ + +#ifndef __NETLINK_CLI_RULE_H_ +#define __NETLINK_CLI_RULE_H_ + +#include + +extern struct rtnl_rule *nl_cli_rule_alloc(void); +extern struct nl_cache *nl_cli_rule_alloc_cache(struct nl_sock *); +extern void nl_cli_rule_parse_family(struct rtnl_rule *, char *); + +#endif diff --git a/libnetwork/libnl3/include/netlink/cli/tc.h b/libnetwork/libnl3/include/netlink/cli/tc.h new file mode 100644 index 0000000..85d2e30 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/cli/tc.h @@ -0,0 +1,39 @@ +/* + * netlink/cli/tc.h CLI Traffic Control Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010-2011 Thomas Graf + */ + +#ifndef __NETLINK_CLI_TC_H_ +#define __NETLINK_CLI_TC_H_ + +#include + +extern void nl_cli_tc_parse_dev(struct rtnl_tc *, struct nl_cache *, char *); +extern void nl_cli_tc_parse_parent(struct rtnl_tc *, char *); +extern void nl_cli_tc_parse_handle(struct rtnl_tc *, char *, int); +extern void nl_cli_tc_parse_mtu(struct rtnl_tc *, char *); +extern void nl_cli_tc_parse_mpu(struct rtnl_tc *, char *); +extern void nl_cli_tc_parse_overhead(struct rtnl_tc *, char *); +extern void nl_cli_tc_parse_linktype(struct rtnl_tc *, char *); +extern void nl_cli_tc_parse_kind(struct rtnl_tc *, char *); + +struct nl_cli_tc_module +{ + const char * tm_name; + enum rtnl_tc_type tm_type; + struct rtnl_tc_ops * tm_ops; + void (*tm_parse_argv)(struct rtnl_tc *, int, char **); + struct nl_list_head tm_list; +}; + +extern struct nl_cli_tc_module *nl_cli_tc_lookup(struct rtnl_tc_ops *); +extern void nl_cli_tc_register(struct nl_cli_tc_module *); +extern void nl_cli_tc_unregister(struct nl_cli_tc_module *); + +#endif diff --git a/libnetwork/libnl3/include/netlink/cli/utils.h b/libnetwork/libnl3/include/netlink/cli/utils.h new file mode 100644 index 0000000..da41c10 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/cli/utils.h @@ -0,0 +1,82 @@ +/* + * src/utils.h Utilities + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2009 Thomas Graf + */ + +#ifndef __NETLINK_CLI_UTILS_H_ +#define __NETLINK_CLI_UTILS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __init +#define __init __attribute__((constructor)) +#endif + +#ifndef __exit +#define __exit __attribute__((destructor)) +#endif + +extern uint32_t nl_cli_parse_u32(const char *); +extern void nl_cli_print_version(void); +extern void nl_cli_fatal(int, const char *, ...); +extern struct nl_addr * nl_cli_addr_parse(const char *, int); +extern int nl_cli_connect(struct nl_sock *, int); +extern struct nl_sock * nl_cli_alloc_socket(void); +extern int nl_cli_parse_dumptype(const char *); +extern int nl_cli_confirm(struct nl_object *, + struct nl_dump_params *, int); + +extern struct nl_cache *nl_cli_alloc_cache(struct nl_sock *, const char *, + int (*ac)(struct nl_sock *, struct nl_cache **)); + +extern void nl_cli_load_module(const char *, const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/data.h b/libnetwork/libnl3/include/netlink/data.h new file mode 100644 index 0000000..071159e --- /dev/null +++ b/libnetwork/libnl3/include/netlink/data.h @@ -0,0 +1,41 @@ +/* + * netlink/data.h Abstract Data + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_DATA_H_ +#define NETLINK_DATA_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct nl_data; + +/* General */ +extern struct nl_data * nl_data_alloc(void *, size_t); +extern struct nl_data * nl_data_alloc_attr(struct nlattr *); +extern struct nl_data * nl_data_clone(struct nl_data *); +extern int nl_data_append(struct nl_data *, void *, size_t); +extern void nl_data_free(struct nl_data *); + +/* Access Functions */ +extern void * nl_data_get(struct nl_data *); +extern size_t nl_data_get_size(struct nl_data *); + +/* Misc */ +extern int nl_data_cmp(struct nl_data *, struct nl_data *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/errno.h b/libnetwork/libnl3/include/netlink/errno.h new file mode 100644 index 0000000..f8b5130 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/errno.h @@ -0,0 +1,64 @@ +/* + * netlink/errno.h Error Numbers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Thomas Graf + */ + +#ifndef NETLINK_ERRNO_H_ +#define NETLINK_ERRNO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define NLE_SUCCESS 0 +#define NLE_FAILURE 1 +#define NLE_INTR 2 +#define NLE_BAD_SOCK 3 +#define NLE_AGAIN 4 +#define NLE_NOMEM 5 +#define NLE_EXIST 6 +#define NLE_INVAL 7 +#define NLE_RANGE 8 +#define NLE_MSGSIZE 9 +#define NLE_OPNOTSUPP 10 +#define NLE_AF_NOSUPPORT 11 +#define NLE_OBJ_NOTFOUND 12 +#define NLE_NOATTR 13 +#define NLE_MISSING_ATTR 14 +#define NLE_AF_MISMATCH 15 +#define NLE_SEQ_MISMATCH 16 +#define NLE_MSG_OVERFLOW 17 +#define NLE_MSG_TRUNC 18 +#define NLE_NOADDR 19 +#define NLE_SRCRT_NOSUPPORT 20 +#define NLE_MSG_TOOSHORT 21 +#define NLE_MSGTYPE_NOSUPPORT 22 +#define NLE_OBJ_MISMATCH 23 +#define NLE_NOCACHE 24 +#define NLE_BUSY 25 +#define NLE_PROTO_MISMATCH 26 +#define NLE_NOACCESS 27 +#define NLE_PERM 28 +#define NLE_PKTLOC_FILE 29 +#define NLE_PARSE_ERR 30 +#define NLE_NODEV 31 +#define NLE_IMMUTABLE 32 +#define NLE_DUMP_INTR 33 + +#define NLE_MAX NLE_DUMP_INTR + +extern const char * nl_geterror(int); +extern void nl_perror(int, const char *); +extern int nl_syserr2nlerr(int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/fib_lookup/lookup.h b/libnetwork/libnl3/include/netlink/fib_lookup/lookup.h new file mode 100644 index 0000000..8bf27b8 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/fib_lookup/lookup.h @@ -0,0 +1,42 @@ +/* + * netlink/fib_lookup/fib_lookup.h FIB Lookup + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_FIB_LOOKUP_H_ +#define NETLINK_FIB_LOOKUP_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct flnl_result; + +extern struct flnl_result * flnl_result_alloc(void); +extern void flnl_result_put(struct flnl_result *); + +extern struct nl_cache * flnl_result_alloc_cache(void); + +extern int flnl_lookup_build_request(struct flnl_request *, + int, + struct nl_msg **); +extern int flnl_lookup(struct nl_sock *, + struct flnl_request *, + struct nl_cache *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/fib_lookup/request.h b/libnetwork/libnl3/include/netlink/fib_lookup/request.h new file mode 100644 index 0000000..60e8820 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/fib_lookup/request.h @@ -0,0 +1,51 @@ +/* + * netlink/fib_lookup/request.h FIB Lookup Request + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_FIB_LOOKUP_REQUEST_H_ +#define NETLINK_FIB_LOOKUP_REQUEST_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct flnl_request; + +#define REQUEST_CAST(ptr) ((struct flnl_request *) (ptr)) + +extern struct flnl_request * flnl_request_alloc(void); + +extern void flnl_request_set_fwmark(struct flnl_request *, + uint64_t); +extern uint64_t flnl_request_get_fwmark(struct flnl_request *); +extern void flnl_request_set_tos(struct flnl_request *, + int); +extern int flnl_request_get_tos(struct flnl_request *); +extern void flnl_request_set_scope(struct flnl_request *, + int); +extern int flnl_request_get_scope(struct flnl_request *); +extern void flnl_request_set_table(struct flnl_request *, + int); +extern int flnl_request_get_table(struct flnl_request *); +extern int flnl_request_set_addr(struct flnl_request *, + struct nl_addr *); +extern struct nl_addr * flnl_request_get_addr(struct flnl_request *); + +extern int flnl_request_cmp(struct flnl_request *, + struct flnl_request *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/genl/ctrl.h b/libnetwork/libnl3/include/netlink/genl/ctrl.h new file mode 100644 index 0000000..26a0a99 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/genl/ctrl.h @@ -0,0 +1,40 @@ +/* + * netlink/genl/ctrl.h Generic Netlink Controller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_GENL_CTRL_H_ +#define NETLINK_GENL_CTRL_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct genl_family; + +extern int genl_ctrl_alloc_cache(struct nl_sock *, + struct nl_cache **); +extern struct genl_family * genl_ctrl_search(struct nl_cache *, int); +extern struct genl_family * genl_ctrl_search_by_name(struct nl_cache *, + const char *); +extern int genl_ctrl_resolve(struct nl_sock *, + const char *); +extern int genl_ctrl_resolve_grp(struct nl_sock *sk, + const char *family, + const char *grp); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/genl/family.h b/libnetwork/libnl3/include/netlink/genl/family.h new file mode 100644 index 0000000..721dc13 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/genl/family.h @@ -0,0 +1,53 @@ +/* + * netlink/genl/family.h Generic Netlink Family + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_GENL_FAMILY_H_ +#define NETLINK_GENL_FAMILY_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct genl_family; + +extern struct genl_family * genl_family_alloc(void); +extern void genl_family_put(struct genl_family *); + +extern unsigned int genl_family_get_id(struct genl_family *); +extern void genl_family_set_id(struct genl_family *, + unsigned int); +extern char * genl_family_get_name(struct genl_family *); +extern void genl_family_set_name(struct genl_family *, + const char *name); +extern uint8_t genl_family_get_version(struct genl_family *); +extern void genl_family_set_version(struct genl_family *, + uint8_t); +extern uint32_t genl_family_get_hdrsize(struct genl_family *); +extern void genl_family_set_hdrsize(struct genl_family *, + uint32_t); +extern uint32_t genl_family_get_maxattr(struct genl_family *); +extern void genl_family_set_maxattr(struct genl_family *, + uint32_t); + +extern int genl_family_add_op(struct genl_family *, + int, int); +extern int genl_family_add_grp(struct genl_family *, + uint32_t , const char *); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/genl/genl.h b/libnetwork/libnl3/include/netlink/genl/genl.h new file mode 100644 index 0000000..364a471 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/genl/genl.h @@ -0,0 +1,46 @@ +/* + * netlink/genl/genl.h Generic Netlink + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_GENL_H_ +#define NETLINK_GENL_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern int genl_connect(struct nl_sock *); +extern int genl_send_simple(struct nl_sock *, int, int, + int, int); + +extern void * genlmsg_put(struct nl_msg *, uint32_t, uint32_t, + int, int, int, uint8_t, uint8_t); + +extern int genlmsg_valid_hdr(struct nlmsghdr *, int); +extern int genlmsg_validate(struct nlmsghdr *, int, int, + struct nla_policy *); +extern int genlmsg_parse(struct nlmsghdr *, int, struct nlattr **, + int, struct nla_policy *); +extern void * genlmsg_data(const struct genlmsghdr *); +extern int genlmsg_len(const struct genlmsghdr *); +extern struct nlattr * genlmsg_attrdata(const struct genlmsghdr *, int); +extern int genlmsg_attrlen(const struct genlmsghdr *, int); + +extern char * genl_op2name(int, int, char *, size_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/genl/mngt.h b/libnetwork/libnl3/include/netlink/genl/mngt.h new file mode 100644 index 0000000..8b0244f --- /dev/null +++ b/libnetwork/libnl3/include/netlink/genl/mngt.h @@ -0,0 +1,87 @@ +/* + * netlink/genl/mngt.h Generic Netlink Management + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_GENL_MNGT_H_ +#define NETLINK_GENL_MNGT_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct nl_cache_ops; + +struct genl_info +{ + struct sockaddr_nl * who; + struct nlmsghdr * nlh; + struct genlmsghdr * genlhdr; + void * userhdr; + struct nlattr ** attrs; +}; + +/** + * @ingroup genl_mngt + * Generic Netlink Command + */ +struct genl_cmd +{ + /** Unique command identifier */ + int c_id; + + /** Name/description of command */ + char * c_name; + + /** + * Maximum attribute identifier, must be provided if + * a message parser is available. + */ + int c_maxattr; + + int (*c_msg_parser)(struct nl_cache_ops *, + struct genl_cmd *, + struct genl_info *, void *); + + /** + * Attribute validation policy (optional) + */ + struct nla_policy * c_attr_policy; +}; + +/** + * @ingroup genl_mngt + * Generic Netlink Operations + */ +struct genl_ops +{ + int o_family; + int o_id; + char * o_name; + struct nl_cache_ops * o_cache_ops; + struct genl_cmd * o_cmds; + int o_ncmds; + + /* linked list of all genl cache operations */ + struct nl_list_head o_list; +}; + + +extern int genl_register(struct nl_cache_ops *); +extern void genl_unregister(struct nl_cache_ops *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/handlers.h b/libnetwork/libnl3/include/netlink/handlers.h new file mode 100644 index 0000000..dfa2809 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/handlers.h @@ -0,0 +1,146 @@ +/* + * netlink/handlers.c default netlink message handlers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_HANDLERS_H_ +#define NETLINK_HANDLERS_H_ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct nl_cb; +struct nl_sock; +struct nl_msg; +struct ucred; + +/** + * @name Callback Typedefs + * @{ + */ + +/** + * nl_recvmsgs() callback for message processing customization + * @ingroup cb + * @arg msg netlink message being processed + * @arg arg argument passwd on through caller + */ +typedef int (*nl_recvmsg_msg_cb_t)(struct nl_msg *msg, void *arg); + +/** + * nl_recvmsgs() callback for error message processing customization + * @ingroup cb + * @arg nla netlink address of the peer + * @arg nlerr netlink error message being processed + * @arg arg argument passed on through caller + */ +typedef int (*nl_recvmsg_err_cb_t)(struct sockaddr_nl *nla, + struct nlmsgerr *nlerr, void *arg); + +/** @} */ + +/** + * Callback actions + * @ingroup cb + */ +enum nl_cb_action { + /** Proceed with wathever would come next */ + NL_OK, + /** Skip this message */ + NL_SKIP, + /** Stop parsing altogether and discard remaining messages */ + NL_STOP, +}; + +/** + * Callback kinds + * @ingroup cb + */ +enum nl_cb_kind { + /** Default handlers (quiet) */ + NL_CB_DEFAULT, + /** Verbose default handlers (error messages printed) */ + NL_CB_VERBOSE, + /** Debug handlers for debugging */ + NL_CB_DEBUG, + /** Customized handler specified by the user */ + NL_CB_CUSTOM, + __NL_CB_KIND_MAX, +}; + +#define NL_CB_KIND_MAX (__NL_CB_KIND_MAX - 1) + +/** + * Callback types + * @ingroup cb + */ +enum nl_cb_type { + /** Message is valid */ + NL_CB_VALID, + /** Last message in a series of multi part messages received */ + NL_CB_FINISH, + /** Report received that data was lost */ + NL_CB_OVERRUN, + /** Message wants to be skipped */ + NL_CB_SKIPPED, + /** Message is an acknowledge */ + NL_CB_ACK, + /** Called for every message received */ + NL_CB_MSG_IN, + /** Called for every message sent out except for nl_sendto() */ + NL_CB_MSG_OUT, + /** Message is malformed and invalid */ + NL_CB_INVALID, + /** Called instead of internal sequence number checking */ + NL_CB_SEQ_CHECK, + /** Sending of an acknowledge message has been requested */ + NL_CB_SEND_ACK, + /** Flag NLM_F_DUMP_INTR is set in message */ + NL_CB_DUMP_INTR, + __NL_CB_TYPE_MAX, +}; + +#define NL_CB_TYPE_MAX (__NL_CB_TYPE_MAX - 1) + +extern struct nl_cb * nl_cb_alloc(enum nl_cb_kind); +extern struct nl_cb * nl_cb_clone(struct nl_cb *); +extern struct nl_cb * nl_cb_get(struct nl_cb *); +extern void nl_cb_put(struct nl_cb *); + +extern int nl_cb_set(struct nl_cb *, enum nl_cb_type, enum nl_cb_kind, + nl_recvmsg_msg_cb_t, void *); +extern int nl_cb_set_all(struct nl_cb *, enum nl_cb_kind, + nl_recvmsg_msg_cb_t, void *); +extern int nl_cb_err(struct nl_cb *, enum nl_cb_kind, nl_recvmsg_err_cb_t, + void *); + +extern void nl_cb_overwrite_recvmsgs(struct nl_cb *, + int (*func)(struct nl_sock *, + struct nl_cb *)); +extern void nl_cb_overwrite_recv(struct nl_cb *, + int (*func)(struct nl_sock *, + struct sockaddr_nl *, + unsigned char **, + struct ucred **)); +extern void nl_cb_overwrite_send(struct nl_cb *, + int (*func)(struct nl_sock *, + struct nl_msg *)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/list.h b/libnetwork/libnl3/include/netlink/list.h new file mode 100644 index 0000000..28712ed --- /dev/null +++ b/libnetwork/libnl3/include/netlink/list.h @@ -0,0 +1,93 @@ +/* + * netlink/list.h Netlink List Utilities + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_LIST_H_ +#define NETLINK_LIST_H_ + +struct nl_list_head +{ + struct nl_list_head * next; + struct nl_list_head * prev; +}; + +static inline void NL_INIT_LIST_HEAD(struct nl_list_head *list) +{ + list->next = list; + list->prev = list; +} + +static inline void __nl_list_add(struct nl_list_head *obj, + struct nl_list_head *prev, + struct nl_list_head *next) +{ + prev->next = obj; + obj->prev = prev; + next->prev = obj; + obj->next = next; +} + +static inline void nl_list_add_tail(struct nl_list_head *obj, + struct nl_list_head *head) +{ + __nl_list_add(obj, head->prev, head); +} + +static inline void nl_list_add_head(struct nl_list_head *obj, + struct nl_list_head *head) +{ + __nl_list_add(obj, head, head->next); +} + +static inline void nl_list_del(struct nl_list_head *obj) +{ + obj->next->prev = obj->prev; + obj->prev->next = obj->next; +} + +static inline int nl_list_empty(struct nl_list_head *head) +{ + return head->next == head; +} + +#define nl_container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - ((size_t) &((type *)0)->member));}) + +#define nl_list_entry(ptr, type, member) \ + nl_container_of(ptr, type, member) + +#define nl_list_at_tail(pos, head, member) \ + ((pos)->member.next == (head)) + +#define nl_list_at_head(pos, head, member) \ + ((pos)->member.prev == (head)) + +#define NL_LIST_HEAD(name) \ + struct nl_list_head name = { &(name), &(name) } + +#define nl_list_first_entry(head, type, member) \ + nl_list_entry((head)->next, type, member) + +#define nl_list_for_each_entry(pos, head, member) \ + for (pos = nl_list_entry((head)->next, typeof(*pos), member); \ + &(pos)->member != (head); \ + (pos) = nl_list_entry((pos)->member.next, typeof(*(pos)), member)) + +#define nl_list_for_each_entry_safe(pos, n, head, member) \ + for (pos = nl_list_entry((head)->next, typeof(*pos), member), \ + n = nl_list_entry(pos->member.next, typeof(*pos), member); \ + &(pos)->member != (head); \ + pos = n, n = nl_list_entry(n->member.next, typeof(*n), member)) + +#define nl_init_list_head(head) \ + do { (head)->next = (head); (head)->prev = (head); } while (0) + +#endif diff --git a/libnetwork/libnl3/include/netlink/msg.h b/libnetwork/libnl3/include/netlink/msg.h new file mode 100644 index 0000000..f3d50ae --- /dev/null +++ b/libnetwork/libnl3/include/netlink/msg.h @@ -0,0 +1,147 @@ +/* + * netlink/msg.c Netlink Messages Interface + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_MSG_H_ +#define NETLINK_MSG_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NL_DONTPAD 0 + +/** + * @ingroup msg + * @brief + * Will cause the netlink port to be set to the port assigned to + * the netlink icoket ust before sending the message off. + * + * @note Requires the use of nl_send_auto()! + */ +#define NL_AUTO_PORT 0 +#define NL_AUTO_PID NL_AUTO_PORT + +/** + * @ingroup msg + * @brief + * May be used to refer to a sequence number which should be + * automatically set just before sending the message off. + * + * @note Requires the use of nl_send_auto()! + */ +#define NL_AUTO_SEQ 0 + +struct nl_msg; +struct nl_tree; +struct ucred; + +extern int nlmsg_size(int); +extern int nlmsg_total_size(int); +extern int nlmsg_padlen(int); + +extern void * nlmsg_data(const struct nlmsghdr *); +extern int nlmsg_datalen(const struct nlmsghdr *); +extern void * nlmsg_tail(const struct nlmsghdr *); + +/* attribute access */ +extern struct nlattr * nlmsg_attrdata(const struct nlmsghdr *, int); +extern int nlmsg_attrlen(const struct nlmsghdr *, int); + +/* message parsing */ +extern int nlmsg_valid_hdr(const struct nlmsghdr *, int); +extern int nlmsg_ok(const struct nlmsghdr *, int); +extern struct nlmsghdr * nlmsg_next(struct nlmsghdr *, int *); +extern int nlmsg_parse(struct nlmsghdr *, int, struct nlattr **, + int, struct nla_policy *); +extern struct nlattr * nlmsg_find_attr(struct nlmsghdr *, int, int); +extern int nlmsg_validate(struct nlmsghdr *, int, int, + struct nla_policy *); + +extern struct nl_msg * nlmsg_alloc(void); +extern struct nl_msg * nlmsg_alloc_size(size_t); +extern struct nl_msg * nlmsg_alloc_simple(int, int); +extern void nlmsg_set_default_size(size_t); +extern struct nl_msg * nlmsg_inherit(struct nlmsghdr *); +extern struct nl_msg * nlmsg_convert(struct nlmsghdr *); +extern void * nlmsg_reserve(struct nl_msg *, size_t, int); +extern int nlmsg_append(struct nl_msg *, void *, size_t, int); +extern int nlmsg_expand(struct nl_msg *, size_t); + +extern struct nlmsghdr * nlmsg_put(struct nl_msg *, uint32_t, uint32_t, + int, int, int); +extern struct nlmsghdr * nlmsg_hdr(struct nl_msg *); +extern void nlmsg_get(struct nl_msg *); +extern void nlmsg_free(struct nl_msg *); + +/* attribute modification */ +extern void nlmsg_set_proto(struct nl_msg *, int); +extern int nlmsg_get_proto(struct nl_msg *); +extern size_t nlmsg_get_max_size(struct nl_msg *); +extern void nlmsg_set_src(struct nl_msg *, struct sockaddr_nl *); +extern struct sockaddr_nl *nlmsg_get_src(struct nl_msg *); +extern void nlmsg_set_dst(struct nl_msg *, struct sockaddr_nl *); +extern struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *); +extern void nlmsg_set_creds(struct nl_msg *, struct ucred *); +extern struct ucred * nlmsg_get_creds(struct nl_msg *); + +extern char * nl_nlmsgtype2str(int, char *, size_t); +extern int nl_str2nlmsgtype(const char *); + +extern char * nl_nlmsg_flags2str(int, char *, size_t); + +extern int nl_msg_parse(struct nl_msg *, + void (*cb)(struct nl_object *, void *), + void *); + +extern void nl_msg_dump(struct nl_msg *, FILE *); + +/** + * @name Iterators + * @{ + */ + +/** + * @ingroup msg + * Iterate over a stream of attributes in a message + * @arg pos loop counter, set to current attribute + * @arg nlh netlink message header + * @arg hdrlen length of family header + * @arg rem initialized to len, holds bytes currently remaining in stream + */ +#define nlmsg_for_each_attr(pos, nlh, hdrlen, rem) \ + nla_for_each_attr(pos, nlmsg_attrdata(nlh, hdrlen), \ + nlmsg_attrlen(nlh, hdrlen), rem) + +/** + * Iterate over a stream of messages + * @arg pos loop counter, set to current message + * @arg head head of message stream + * @arg len length of message stream + */ +#define nlmsg_for_each(pos, head, len) \ + for (int rem = len, pos = head; \ + nlmsg_ok(pos, rem); \ + pos = nlmsg_next(pos, &rem)) + +#define nlmsg_for_each_msg(pos, head, len, rem) \ + nlmsg_for_each(pos, head, len) + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/netfilter/ct.h b/libnetwork/libnl3/include/netlink/netfilter/ct.h new file mode 100644 index 0000000..57fbe53 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/netfilter/ct.h @@ -0,0 +1,126 @@ +/* + * netlink/netfilter/ct.h Conntrack + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + * Copyright (c) 2007 Philip Craig + * Copyright (c) 2007 Secure Computing Corporation + */ + +#ifndef NETLINK_CT_H_ +#define NETLINK_CT_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct nfnl_ct; + +extern struct nl_object_ops ct_obj_ops; + +extern struct nfnl_ct * nfnl_ct_alloc(void); +extern int nfnl_ct_alloc_cache(struct nl_sock *, struct nl_cache **); + +extern int nfnlmsg_ct_group(struct nlmsghdr *); +extern int nfnlmsg_ct_parse(struct nlmsghdr *, struct nfnl_ct **); + +extern void nfnl_ct_get(struct nfnl_ct *); +extern void nfnl_ct_put(struct nfnl_ct *); + +extern int nfnl_ct_dump_request(struct nl_sock *); + +extern int nfnl_ct_build_add_request(const struct nfnl_ct *, int, + struct nl_msg **); +extern int nfnl_ct_add(struct nl_sock *, const struct nfnl_ct *, int); + +extern int nfnl_ct_build_delete_request(const struct nfnl_ct *, int, + struct nl_msg **); +extern int nfnl_ct_del(struct nl_sock *, const struct nfnl_ct *, int); + +extern int nfnl_ct_build_query_request(const struct nfnl_ct *, int, + struct nl_msg **); +extern int nfnl_ct_query(struct nl_sock *, const struct nfnl_ct *, int); + +extern void nfnl_ct_set_family(struct nfnl_ct *, uint8_t); +extern uint8_t nfnl_ct_get_family(const struct nfnl_ct *); + +extern void nfnl_ct_set_proto(struct nfnl_ct *, uint8_t); +extern int nfnl_ct_test_proto(const struct nfnl_ct *); +extern uint8_t nfnl_ct_get_proto(const struct nfnl_ct *); + +extern void nfnl_ct_set_tcp_state(struct nfnl_ct *, uint8_t); +extern int nfnl_ct_test_tcp_state(const struct nfnl_ct *); +extern uint8_t nfnl_ct_get_tcp_state(const struct nfnl_ct *); +extern char * nfnl_ct_tcp_state2str(uint8_t, char *, size_t); +extern int nfnl_ct_str2tcp_state(const char *name); + +extern void nfnl_ct_set_status(struct nfnl_ct *, uint32_t); +extern void nfnl_ct_unset_status(struct nfnl_ct *, uint32_t); +extern uint32_t nfnl_ct_get_status(const struct nfnl_ct *); +extern char * nfnl_ct_status2str(int, char *, size_t); +extern int nfnl_ct_str2status(const char *); + +extern void nfnl_ct_set_timeout(struct nfnl_ct *, uint32_t); +extern int nfnl_ct_test_timeout(const struct nfnl_ct *); +extern uint32_t nfnl_ct_get_timeout(const struct nfnl_ct *); + +extern void nfnl_ct_set_mark(struct nfnl_ct *, uint32_t); +extern int nfnl_ct_test_mark(const struct nfnl_ct *); +extern uint32_t nfnl_ct_get_mark(const struct nfnl_ct *); + +extern void nfnl_ct_set_use(struct nfnl_ct *, uint32_t); +extern int nfnl_ct_test_use(const struct nfnl_ct *); +extern uint32_t nfnl_ct_get_use(const struct nfnl_ct *); + +extern void nfnl_ct_set_id(struct nfnl_ct *, uint32_t); +extern int nfnl_ct_test_id(const struct nfnl_ct *); +extern uint32_t nfnl_ct_get_id(const struct nfnl_ct *); + +extern int nfnl_ct_set_src(struct nfnl_ct *, int, struct nl_addr *); +extern struct nl_addr * nfnl_ct_get_src(const struct nfnl_ct *, int); + +extern int nfnl_ct_set_dst(struct nfnl_ct *, int, struct nl_addr *); +extern struct nl_addr * nfnl_ct_get_dst(const struct nfnl_ct *, int); + +extern void nfnl_ct_set_src_port(struct nfnl_ct *, int, uint16_t); +extern int nfnl_ct_test_src_port(const struct nfnl_ct *, int); +extern uint16_t nfnl_ct_get_src_port(const struct nfnl_ct *, int); + +extern void nfnl_ct_set_dst_port(struct nfnl_ct *, int, uint16_t); +extern int nfnl_ct_test_dst_port(const struct nfnl_ct *, int); +extern uint16_t nfnl_ct_get_dst_port(const struct nfnl_ct *, int); + +extern void nfnl_ct_set_icmp_id(struct nfnl_ct *, int, uint16_t); +extern int nfnl_ct_test_icmp_id(const struct nfnl_ct *, int); +extern uint16_t nfnl_ct_get_icmp_id(const struct nfnl_ct *, int); + +extern void nfnl_ct_set_icmp_type(struct nfnl_ct *, int, uint8_t); +extern int nfnl_ct_test_icmp_type(const struct nfnl_ct *, int); +extern uint8_t nfnl_ct_get_icmp_type(const struct nfnl_ct *, int); + +extern void nfnl_ct_set_icmp_code(struct nfnl_ct *, int, uint8_t); +extern int nfnl_ct_test_icmp_code(const struct nfnl_ct *, int); +extern uint8_t nfnl_ct_get_icmp_code(const struct nfnl_ct *, int); + +extern void nfnl_ct_set_packets(struct nfnl_ct *, int, uint64_t); +extern int nfnl_ct_test_packets(const struct nfnl_ct *, int); +extern uint64_t nfnl_ct_get_packets(const struct nfnl_ct *,int); + +extern void nfnl_ct_set_bytes(struct nfnl_ct *, int, uint64_t); +extern int nfnl_ct_test_bytes(const struct nfnl_ct *, int); +extern uint64_t nfnl_ct_get_bytes(const struct nfnl_ct *, int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/netfilter/log.h b/libnetwork/libnl3/include/netlink/netfilter/log.h new file mode 100644 index 0000000..2002fa8 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/netfilter/log.h @@ -0,0 +1,109 @@ +/* + * netlink/netfilter/log.h Netfilter Log + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + * Copyright (c) 2007 Philip Craig + * Copyright (c) 2007 Secure Computing Corporation + * Copyright (c) 2008 Patrick McHardy + */ + +#ifndef NETLINK_LOG_H_ +#define NETLINK_LOG_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct nl_sock; +struct nlmsghdr; +struct nfnl_log; + +extern struct nl_object_ops log_obj_ops; + +enum nfnl_log_copy_mode { + NFNL_LOG_COPY_NONE, + NFNL_LOG_COPY_META, + NFNL_LOG_COPY_PACKET, +}; + +enum nfnl_log_flags { + NFNL_LOG_FLAG_SEQ = 0x1, + NFNL_LOG_FLAG_SEQ_GLOBAL = 0x2, +}; + +/* General */ +extern struct nfnl_log * nfnl_log_alloc(void); +extern int nfnlmsg_log_parse(struct nlmsghdr *, + struct nfnl_log **); + +extern void nfnl_log_get(struct nfnl_log *); +extern void nfnl_log_put(struct nfnl_log *); + +/* Attributes */ +extern void nfnl_log_set_group(struct nfnl_log *, uint16_t); +extern int nfnl_log_test_group(const struct nfnl_log *); +extern uint16_t nfnl_log_get_group(const struct nfnl_log *); + +extern void nfnl_log_set_copy_mode(struct nfnl_log *, + enum nfnl_log_copy_mode); +extern int nfnl_log_test_copy_mode(const struct nfnl_log *); +extern enum nfnl_log_copy_mode nfnl_log_get_copy_mode(const struct nfnl_log *); + +extern char * nfnl_log_copy_mode2str(enum nfnl_log_copy_mode, + char *, size_t); +extern enum nfnl_log_copy_mode nfnl_log_str2copy_mode(const char *); + +extern void nfnl_log_set_copy_range(struct nfnl_log *, uint32_t); +extern int nfnl_log_test_copy_range(const struct nfnl_log *); +extern uint32_t nfnl_log_get_copy_range(const struct nfnl_log *); + +extern void nfnl_log_set_flush_timeout(struct nfnl_log *, uint32_t); +extern int nfnl_log_test_flush_timeout(const struct nfnl_log *); +extern uint32_t nfnl_log_get_flush_timeout(const struct nfnl_log *); + +extern void nfnl_log_set_alloc_size(struct nfnl_log *, uint32_t); +extern int nfnl_log_test_alloc_size(const struct nfnl_log *); +extern uint32_t nfnl_log_get_alloc_size(const struct nfnl_log *); + +extern void nfnl_log_set_queue_threshold(struct nfnl_log *, uint32_t); +extern int nfnl_log_test_queue_threshold(const struct nfnl_log *); +extern uint32_t nfnl_log_get_queue_threshold(const struct nfnl_log *); + +extern void nfnl_log_set_flags(struct nfnl_log *, unsigned int); +extern void nfnl_log_unset_flags(struct nfnl_log *, unsigned int); +extern unsigned int nfnl_log_get_flags(const struct nfnl_log *); + +extern char * nfnl_log_flags2str(unsigned int, char *, size_t); +extern unsigned int nfnl_log_str2flags(const char *); + +extern int nfnl_log_build_pf_bind(uint8_t, struct nl_msg **); +extern int nfnl_log_pf_bind(struct nl_sock *, uint8_t); + +extern int nfnl_log_build_pf_unbind(uint8_t, struct nl_msg **); +extern int nfnl_log_pf_unbind(struct nl_sock *, uint8_t); + +extern int nfnl_log_build_create_request(const struct nfnl_log *, + struct nl_msg **); +extern int nfnl_log_create(struct nl_sock *, const struct nfnl_log *); + +extern int nfnl_log_build_change_request(const struct nfnl_log *, + struct nl_msg **); +extern int nfnl_log_change(struct nl_sock *, const struct nfnl_log *); + +extern int nfnl_log_build_delete_request(const struct nfnl_log *, + struct nl_msg **); +extern int nfnl_log_delete(struct nl_sock *, const struct nfnl_log *); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/libnetwork/libnl3/include/netlink/netfilter/log_msg.h b/libnetwork/libnl3/include/netlink/netfilter/log_msg.h new file mode 100644 index 0000000..63b0f64 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/netfilter/log_msg.h @@ -0,0 +1,98 @@ +/* + * netlink/netfilter/log_msg.h Netfilter Log Message + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + * Copyright (c) 2007 Philip Craig + * Copyright (c) 2007 Secure Computing Corporation + * Copyright (c) 2008 Patrick McHardy + */ + +#ifndef NETLINK_LOG_MSG_H_ +#define NETLINK_LOG_MSG_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct nlmsghdr; +struct nfnl_log_msg; + +extern struct nl_object_ops log_msg_obj_ops; + +/* General */ +extern struct nfnl_log_msg *nfnl_log_msg_alloc(void); +extern int nfnlmsg_log_msg_parse(struct nlmsghdr *, + struct nfnl_log_msg **); + +extern void nfnl_log_msg_get(struct nfnl_log_msg *); +extern void nfnl_log_msg_put(struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_family(struct nfnl_log_msg *, uint8_t); +extern uint8_t nfnl_log_msg_get_family(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_hwproto(struct nfnl_log_msg *, uint16_t); +extern int nfnl_log_msg_test_hwproto(const struct nfnl_log_msg *); +extern uint16_t nfnl_log_msg_get_hwproto(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_hook(struct nfnl_log_msg *, uint8_t); +extern int nfnl_log_msg_test_hook(const struct nfnl_log_msg *); +extern uint8_t nfnl_log_msg_get_hook(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_mark(struct nfnl_log_msg *, uint32_t); +extern int nfnl_log_msg_test_mark(const struct nfnl_log_msg *); +extern uint32_t nfnl_log_msg_get_mark(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_timestamp(struct nfnl_log_msg *, + struct timeval *); +extern const struct timeval *nfnl_log_msg_get_timestamp(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_indev(struct nfnl_log_msg *, uint32_t); +extern uint32_t nfnl_log_msg_get_indev(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_outdev(struct nfnl_log_msg *, uint32_t); +extern uint32_t nfnl_log_msg_get_outdev(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_physindev(struct nfnl_log_msg *, uint32_t); +extern uint32_t nfnl_log_msg_get_physindev(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_physoutdev(struct nfnl_log_msg *, uint32_t); +extern uint32_t nfnl_log_msg_get_physoutdev(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_hwaddr(struct nfnl_log_msg *, uint8_t *, int); +extern const uint8_t * nfnl_log_msg_get_hwaddr(const struct nfnl_log_msg *, int *); + +extern int nfnl_log_msg_set_payload(struct nfnl_log_msg *, uint8_t *, int); +extern const void * nfnl_log_msg_get_payload(const struct nfnl_log_msg *, int *); + +extern int nfnl_log_msg_set_prefix(struct nfnl_log_msg *, void *); +extern const char * nfnl_log_msg_get_prefix(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_uid(struct nfnl_log_msg *, uint32_t); +extern int nfnl_log_msg_test_uid(const struct nfnl_log_msg *); +extern uint32_t nfnl_log_msg_get_uid(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_gid(struct nfnl_log_msg *, uint32_t); +extern int nfnl_log_msg_test_gid(const struct nfnl_log_msg *); +extern uint32_t nfnl_log_msg_get_gid(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_seq(struct nfnl_log_msg *, uint32_t); +extern int nfnl_log_msg_test_seq(const struct nfnl_log_msg *); +extern uint32_t nfnl_log_msg_get_seq(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_seq_global(struct nfnl_log_msg *, uint32_t); +extern int nfnl_log_msg_test_seq_global(const struct nfnl_log_msg *); +extern uint32_t nfnl_log_msg_get_seq_global(const struct nfnl_log_msg *); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/libnetwork/libnl3/include/netlink/netfilter/netfilter.h b/libnetwork/libnl3/include/netlink/netfilter/netfilter.h new file mode 100644 index 0000000..dd3589c --- /dev/null +++ b/libnetwork/libnl3/include/netlink/netfilter/netfilter.h @@ -0,0 +1,31 @@ +/* + * netlink/netfilter/netfilter.h Netfilter generic functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Patrick McHardy + */ + +#ifndef NETLINK_NETFILTER_H_ +#define NETLINK_NETFILTER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern char * nfnl_verdict2str(unsigned int, char *, size_t); +extern unsigned int nfnl_str2verdict(const char *); + +extern char * nfnl_inet_hook2str(unsigned int, char *, size_t); +extern unsigned int nfnl_str2inet_hook(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/netfilter/nfnl.h b/libnetwork/libnl3/include/netlink/netfilter/nfnl.h new file mode 100644 index 0000000..8da4ba1 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/netfilter/nfnl.h @@ -0,0 +1,44 @@ +/* + * netlink/nfnl/nfnl.h Netfilter Netlink + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + * Copyright (c) 2007 Philip Craig + * Copyright (c) 2007 Secure Computing Corporation + */ + +#ifndef NETLINK_NFNL_H_ +#define NETLINK_NFNL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NFNL_HDRLEN NLMSG_ALIGN(sizeof(struct nfgenmsg)) +#define NFNLMSG_TYPE(subsys, subtype) (((subsys) << 8) | (subtype)) + +extern int nfnl_connect(struct nl_sock *); + +extern uint8_t nfnlmsg_subsys(struct nlmsghdr *); +extern uint8_t nfnlmsg_subtype(struct nlmsghdr *); +extern uint8_t nfnlmsg_family(struct nlmsghdr *); +extern uint16_t nfnlmsg_res_id(struct nlmsghdr *); + +extern int nfnl_send_simple(struct nl_sock *, uint8_t, uint8_t, + int, uint8_t, uint16_t); +extern struct nl_msg * nfnlmsg_alloc_simple(uint8_t, uint8_t, int, + uint8_t, uint16_t); +extern int nfnlmsg_put(struct nl_msg *, uint32_t, uint32_t, + uint8_t, uint8_t, int, uint8_t, uint16_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/netfilter/queue.h b/libnetwork/libnl3/include/netlink/netfilter/queue.h new file mode 100644 index 0000000..664610d --- /dev/null +++ b/libnetwork/libnl3/include/netlink/netfilter/queue.h @@ -0,0 +1,90 @@ +/* + * netlink/netfilter/queue.h Netfilter Queue + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2007, 2008 Patrick McHardy + */ + +#ifndef NETLINK_QUEUE_H_ +#define NETLINK_QUEUE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct nl_sock; +struct nlmsghdr; +struct nfnl_queue; + +extern struct nl_object_ops queue_obj_ops; + +enum nfnl_queue_copy_mode { + NFNL_QUEUE_COPY_NONE, + NFNL_QUEUE_COPY_META, + NFNL_QUEUE_COPY_PACKET, +}; + +/* General */ +extern struct nl_sock * nfnl_queue_socket_alloc(void); + +extern struct nfnl_queue * nfnl_queue_alloc(void); + +extern void nfnl_queue_get(struct nfnl_queue *); +extern void nfnl_queue_put(struct nfnl_queue *); + +/* Attributes */ +extern void nfnl_queue_set_group(struct nfnl_queue *, uint16_t); +extern int nfnl_queue_test_group(const struct nfnl_queue *); +extern uint16_t nfnl_queue_get_group(const struct nfnl_queue *); + +extern void nfnl_queue_set_maxlen(struct nfnl_queue *, uint32_t); +extern int nfnl_queue_test_maxlen(const struct nfnl_queue *); +extern uint32_t nfnl_queue_get_maxlen(const struct nfnl_queue *); + +extern void nfnl_queue_set_copy_mode(struct nfnl_queue *, + enum nfnl_queue_copy_mode); +extern int nfnl_queue_test_copy_mode(const struct nfnl_queue *); +extern enum nfnl_queue_copy_mode nfnl_queue_get_copy_mode(const struct nfnl_queue *); + +extern char * nfnl_queue_copy_mode2str(enum nfnl_queue_copy_mode, + char *, size_t); +extern enum nfnl_queue_copy_mode nfnl_queue_str2copy_mode(const char *); + +extern void nfnl_queue_set_copy_range(struct nfnl_queue *, + uint32_t); +extern int nfnl_queue_test_copy_range(const struct nfnl_queue *); +extern uint32_t nfnl_queue_get_copy_range(const struct nfnl_queue *); + +extern int nfnl_queue_build_pf_bind(uint8_t, struct nl_msg **); +extern int nfnl_queue_pf_bind(struct nl_sock *, uint8_t); + +extern int nfnl_queue_build_pf_unbind(uint8_t, struct nl_msg **); +extern int nfnl_queue_pf_unbind(struct nl_sock *, uint8_t); + +extern int nfnl_queue_build_create_request(const struct nfnl_queue *, + struct nl_msg **); +extern int nfnl_queue_create(struct nl_sock *, + const struct nfnl_queue *); + +extern int nfnl_queue_build_change_request(const struct nfnl_queue *, + struct nl_msg **); +extern int nfnl_queue_change(struct nl_sock *, + const struct nfnl_queue *); + +extern int nfnl_queue_build_delete_request(const struct nfnl_queue *, + struct nl_msg **); +extern int nfnl_queue_delete(struct nl_sock *, + const struct nfnl_queue *); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/libnetwork/libnl3/include/netlink/netfilter/queue_msg.h b/libnetwork/libnl3/include/netlink/netfilter/queue_msg.h new file mode 100644 index 0000000..24ed081 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/netfilter/queue_msg.h @@ -0,0 +1,104 @@ +/* + * netlink/netfilter/queue_msg.h Netfilter Queue Messages + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2007, 2008 Patrick McHardy + */ + +#ifndef NETLINK_QUEUE_MSG_H_ +#define NETLINK_QUEUE_MSG_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct nl_sock; +struct nlmsghdr; +struct nfnl_queue_msg; + +extern struct nl_object_ops queue_msg_obj_ops; + +/* General */ +extern struct nfnl_queue_msg * nfnl_queue_msg_alloc(void); +extern int nfnlmsg_queue_msg_parse(struct nlmsghdr *, + struct nfnl_queue_msg **); + +extern void nfnl_queue_msg_get(struct nfnl_queue_msg *); +extern void nfnl_queue_msg_put(struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_group(struct nfnl_queue_msg *, uint16_t); +extern int nfnl_queue_msg_test_group(const struct nfnl_queue_msg *); +extern uint16_t nfnl_queue_msg_get_group(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_family(struct nfnl_queue_msg *, uint8_t); +extern int nfnl_queue_msg_test_family(const struct nfnl_queue_msg *); +extern uint8_t nfnl_queue_msg_get_family(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_packetid(struct nfnl_queue_msg *, uint32_t); +extern int nfnl_queue_msg_test_packetid(const struct nfnl_queue_msg *); +extern uint32_t nfnl_queue_msg_get_packetid(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_hwproto(struct nfnl_queue_msg *, uint16_t); +extern int nfnl_queue_msg_test_hwproto(const struct nfnl_queue_msg *); +extern uint16_t nfnl_queue_msg_get_hwproto(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_hook(struct nfnl_queue_msg *, uint8_t); +extern int nfnl_queue_msg_test_hook(const struct nfnl_queue_msg *); +extern uint8_t nfnl_queue_msg_get_hook(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_mark(struct nfnl_queue_msg *, uint32_t); +extern int nfnl_queue_msg_test_mark(const struct nfnl_queue_msg *); +extern uint32_t nfnl_queue_msg_get_mark(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_timestamp(struct nfnl_queue_msg *, + struct timeval *); +extern int nfnl_queue_msg_test_timestamp(const struct nfnl_queue_msg *); +extern const struct timeval * nfnl_queue_msg_get_timestamp(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_indev(struct nfnl_queue_msg *, uint32_t); +extern int nfnl_queue_msg_test_indev(const struct nfnl_queue_msg *); +extern uint32_t nfnl_queue_msg_get_indev(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_outdev(struct nfnl_queue_msg *, uint32_t); +extern int nfnl_queue_msg_test_outdev(const struct nfnl_queue_msg *); +extern uint32_t nfnl_queue_msg_get_outdev(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_physindev(struct nfnl_queue_msg *, uint32_t); +extern int nfnl_queue_msg_test_physindev(const struct nfnl_queue_msg *); +extern uint32_t nfnl_queue_msg_get_physindev(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_physoutdev(struct nfnl_queue_msg *, uint32_t); +extern int nfnl_queue_msg_test_physoutdev(const struct nfnl_queue_msg *); +extern uint32_t nfnl_queue_msg_get_physoutdev(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_hwaddr(struct nfnl_queue_msg *, uint8_t *, int); +extern int nfnl_queue_msg_test_hwaddr(const struct nfnl_queue_msg *); +extern const uint8_t * nfnl_queue_msg_get_hwaddr(const struct nfnl_queue_msg *, int *); + +extern int nfnl_queue_msg_set_payload(struct nfnl_queue_msg *, uint8_t *, int); +extern int nfnl_queue_msg_test_payload(const struct nfnl_queue_msg *); +extern const void * nfnl_queue_msg_get_payload(const struct nfnl_queue_msg *, int *); + +extern void nfnl_queue_msg_set_verdict(struct nfnl_queue_msg *, + unsigned int); +extern int nfnl_queue_msg_test_verdict(const struct nfnl_queue_msg *); +extern unsigned int nfnl_queue_msg_get_verdict(const struct nfnl_queue_msg *); + +extern struct nl_msg * nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *); +extern int nfnl_queue_msg_send_verdict(struct nl_sock *, + const struct nfnl_queue_msg *); +extern int nfnl_queue_msg_send_verdict_payload(struct nl_sock *, + const struct nfnl_queue_msg *, + const void *, unsigned ); +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/libnetwork/libnl3/include/netlink/netlink-compat.h b/libnetwork/libnl3/include/netlink/netlink-compat.h new file mode 100644 index 0000000..17ec9fc --- /dev/null +++ b/libnetwork/libnl3/include/netlink/netlink-compat.h @@ -0,0 +1,50 @@ +/* + * netlink/netlink-compat.h Netlink Compatability + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_COMPAT_H_ +#define NETLINK_COMPAT_H_ + +#if !defined _LINUX_SOCKET_H && !defined _BITS_SOCKADDR_H +typedef unsigned short sa_family_t; +#endif + +#ifndef IFNAMSIZ +/** Maximum length of a interface name */ +#define IFNAMSIZ 16 +#endif + +/* patch 2.4.x if_arp */ +#ifndef ARPHRD_INFINIBAND +#define ARPHRD_INFINIBAND 32 +#endif + +/* patch 2.4.x eth header file */ +#ifndef ETH_P_MPLS_UC +#define ETH_P_MPLS_UC 0x8847 +#endif + +#ifndef ETH_P_MPLS_MC +#define ETH_P_MPLS_MC 0x8848 +#endif + +#ifndef ETH_P_EDP2 +#define ETH_P_EDP2 0x88A2 +#endif + +#ifndef ETH_P_HDLC +#define ETH_P_HDLC 0x0019 +#endif + +#ifndef AF_LLC +#define AF_LLC 26 +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/netlink-kernel.h b/libnetwork/libnl3/include/netlink/netlink-kernel.h new file mode 100644 index 0000000..f09051d --- /dev/null +++ b/libnetwork/libnl3/include/netlink/netlink-kernel.h @@ -0,0 +1,293 @@ +#ifndef __NETLINK_KERNEL_H_ +#define __NETLINK_KERNEL_H_ + +#if 0 + +/* + * FIXME: Goal is to preseve the documentation but make it simple + * to keep linux/netlink.h in sync. Maybe use named documentation + * sections. + */ + +/** + * Netlink socket address + * @ingroup nl + */ +struct sockaddr_nl +{ + /** socket family (AF_NETLINK) */ + sa_family_t nl_family; + + /** Padding (unused) */ + unsigned short nl_pad; + + /** Unique process ID */ + uint32_t nl_pid; + + /** Multicast group subscriptions */ + uint32_t nl_groups; +}; + +/** + * @addtogroup msg + * @{ + */ + + +/** + * Netlink message header + */ +struct nlmsghdr +{ + /** Length of message including header and padding. */ + uint32_t nlmsg_len; + + /** Message type (content type) */ + uint16_t nlmsg_type; + + /** Message flags */ + uint16_t nlmsg_flags; + + /** Sequence number of message \see core_sk_seq_num. */ + uint32_t nlmsg_seq; + + /** Netlink port */ + uint32_t nlmsg_pid; +}; + +/** + * @name Standard message flags + * @{ + */ + +/** + * Must be set on all request messages (typically from user space to + * kernel space). + */ +#define NLM_F_REQUEST 1 + +/** + * Indicates the message is part of a multipart message terminated + * by NLMSG_DONE. + */ +#define NLM_F_MULTI 2 + +/** + * Request for an acknowledgment on success. + */ +#define NLM_F_ACK 4 + +/** + * Echo this request + */ +#define NLM_F_ECHO 8 + +/** @} */ + +/** + * @name Additional message flags for GET requests + * @{ + */ + +/** + * Return the complete table instead of a single entry. + */ +#define NLM_F_ROOT 0x100 + +/** + * Return all entries matching criteria passed in message content. + */ +#define NLM_F_MATCH 0x200 + +/** + * Return an atomic snapshot of the table being referenced. This + * may require special privileges because it has the potential to + * interrupt service in the FE for a longer time. + */ +#define NLM_F_ATOMIC 0x400 + +/** + * Dump all entries + */ +#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH) + +/** @} */ + +/** + * @name Additional messsage flags for NEW requests + * @{ + */ + +/** + * Replace existing matching config object with this request. + */ +#define NLM_F_REPLACE 0x100 + +/** + * Don't replace the config object if it already exists. + */ +#define NLM_F_EXCL 0x200 + +/** + * Create config object if it doesn't already exist. + */ +#define NLM_F_CREATE 0x400 + +/** + * Add to the end of the object list. + */ +#define NLM_F_APPEND 0x800 + +/** @} */ + +/** + * @name Standard Message types + * @{ + */ + +/** + * No operation, message must be ignored + */ +#define NLMSG_NOOP 0x1 + +/** + * The message signals an error and the payload contains a nlmsgerr + * structure. This can be looked at as a NACK and typically it is + * from FEC to CPC. + */ +#define NLMSG_ERROR 0x2 + +/** + * Message terminates a multipart message. + */ +#define NLMSG_DONE 0x3 + +/** + * The message signals that data got lost + */ +#define NLMSG_OVERRUN 0x4 + +/** + * Lower limit of reserved message types + */ +#define NLMSG_MIN_TYPE 0x10 + +/** @} */ + +/** + * Netlink error message header + */ +struct nlmsgerr +{ + /** Error code (errno number) */ + int error; + + /** Original netlink message causing the error */ + struct nlmsghdr msg; +}; + +struct nl_pktinfo +{ + __u32 group; +}; + +/** + * Netlink alignment constant, all boundries within messages must be align to this. + * + * See \ref core_msg_fmt_align for more information on message alignment. + */ +#define NLMSG_ALIGNTO 4 + +/** + * Returns \p len properly aligned to NLMSG_ALIGNTO. + * + * See \ref core_msg_fmt_align for more information on message alignment. + */ +#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) ) + +/** + * Length of a netlink message header including padding. + * + * See \ref core_msg_fmt_align for more information on message alignment. + */ +#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) + +/** @} */ + +/** + * @addtogroup attr + * @{ + */ + +/* + */ + +/** + * Netlink attribute structure + * + * @code + * <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)--> + * +---------------------+- - -+- - - - - - - - - -+- - -+ + * | Header | Pad | Payload | Pad | + * | (struct nlattr) | ing | | ing | + * +---------------------+- - -+- - - - - - - - - -+- - -+ + * <-------------- nlattr->nla_len --------------> + * @endcode + */ +struct nlattr { + /** + * Attribute length in bytes including header + */ + __u16 nla_len; + + /** + * Netlink attribute type + */ + __u16 nla_type; +}; + +/** + * @name Attribute Type Flags + * + * @code + * nla_type (16 bits) + * +---+---+-------------------------------+ + * | N | O | Attribute Type | + * +---+---+-------------------------------+ + * N := Carries nested attributes + * O := Payload stored in network byte order + * @endcode + * + * @note The N and O flag are mutually exclusive. + * + * @{ + */ + +/* + */ +#define NLA_F_NESTED (1 << 15) +#define NLA_F_NET_BYTEORDER (1 << 14) +#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER) + +/** @} */ + +#define NLA_ALIGNTO 4 + +/** + * Returns \p len properly aligned to NLA_ALIGNTO. + * + * See \ref core_msg_fmt_align for more information on message alignment. + */ +#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1)) + +/** + * Length of a netlink attribute header including padding. + * + * See \ref core_msg_fmt_align for more information on message alignment. + */ +#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr))) + +/** @} */ + +#endif +#endif /* __LINUX_NETLINK_H */ diff --git a/libnetwork/libnl3/include/netlink/netlink.h b/libnetwork/libnl3/include/netlink/netlink.h new file mode 100644 index 0000000..0768708 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/netlink.h @@ -0,0 +1,93 @@ +/* + * netlink/netlink.h Netlink Interface + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_NETLINK_H_ +#define NETLINK_NETLINK_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ucred; + +extern int nl_debug; +extern struct nl_dump_params nl_debug_dp; + +/* Connection Management */ +extern int nl_connect(struct nl_sock *, int); +extern void nl_close(struct nl_sock *); + +/* Send */ +extern int nl_sendto(struct nl_sock *, void *, size_t); +extern int nl_sendmsg(struct nl_sock *, struct nl_msg *, + struct msghdr *); +extern int nl_send(struct nl_sock *, struct nl_msg *); +extern int nl_send_iovec(struct nl_sock *, struct nl_msg *, + struct iovec *, unsigned); +extern void nl_complete_msg(struct nl_sock *, + struct nl_msg *); +extern void nl_auto_complete(struct nl_sock *, + struct nl_msg *); +extern int nl_send_auto(struct nl_sock *, struct nl_msg *); +extern int nl_send_auto_complete(struct nl_sock *, + struct nl_msg *); +extern int nl_send_sync(struct nl_sock *, struct nl_msg *); +extern int nl_send_simple(struct nl_sock *, int, int, + void *, size_t); + +/* Receive */ +extern int nl_recv(struct nl_sock *, + struct sockaddr_nl *, unsigned char **, + struct ucred **); + +extern int nl_recvmsgs(struct nl_sock *, struct nl_cb *); + +extern int nl_recvmsgs_default(struct nl_sock *); + +extern int nl_wait_for_ack(struct nl_sock *); + +extern int nl_pickup(struct nl_sock *, + int (*parser)(struct nl_cache_ops *, + struct sockaddr_nl *, + struct nlmsghdr *, + struct nl_parser_param *), + struct nl_object **); +/* Netlink Family Translations */ +extern char * nl_nlfamily2str(int, char *, size_t); +extern int nl_str2nlfamily(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/object-api.h b/libnetwork/libnl3/include/netlink/object-api.h new file mode 100644 index 0000000..70a4ddd --- /dev/null +++ b/libnetwork/libnl3/include/netlink/object-api.h @@ -0,0 +1,348 @@ +/* + * netlink/object-api.c Object API + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2007 Thomas Graf + */ + +#ifndef NETLINK_OBJECT_API_H_ +#define NETLINK_OBJECT_API_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @ingroup object + * @defgroup object_api Object API + * @brief + * + * @par 1) Object Definition + * @code + * // Define your object starting with the common object header + * struct my_obj { + * NLHDR_COMMON + * int my_data; + * }; + * + * // Fill out the object operations structure + * struct nl_object_ops my_ops = { + * .oo_name = "my_obj", + * .oo_size = sizeof(struct my_obj), + * }; + * + * // At this point the object can be allocated, you may want to provide a + * // separate _alloc() function to ease allocting objects of this kind. + * struct nl_object *obj = nl_object_alloc(&my_ops); + * + * // And release it again... + * nl_object_put(obj); + * @endcode + * + * @par 2) Allocating additional data + * @code + * // You may require to allocate additional data and store it inside + * // object, f.e. assuming there is a field `ptr'. + * struct my_obj { + * NLHDR_COMMON + * void * ptr; + * }; + * + * // And at some point you may assign allocated data to this field: + * my_obj->ptr = calloc(1, ...); + * + * // In order to not introduce any memory leaks you have to release + * // this data again when the last reference is given back. + * static void my_obj_free_data(struct nl_object *obj) + * { + * struct my_obj *my_obj = nl_object_priv(obj); + * + * free(my_obj->ptr); + * } + * + * // Also when the object is cloned, you must ensure for your pointer + * // stay valid even if one of the clones is freed by either making + * // a clone as well or increase the reference count. + * static int my_obj_clone(struct nl_object *src, struct nl_object *dst) + * { + * struct my_obj *my_src = nl_object_priv(src); + * struct my_obj *my_dst = nl_object_priv(dst); + * + * if (src->ptr) { + * dst->ptr = calloc(1, ...); + * memcpy(dst->ptr, src->ptr, ...); + * } + * } + * + * struct nl_object_ops my_ops = { + * ... + * .oo_free_data = my_obj_free_data, + * .oo_clone = my_obj_clone, + * }; + * @endcode + * + * @par 3) Object Dumping + * @code + * static int my_obj_dump_detailed(struct nl_object *obj, + * struct nl_dump_params *params) + * { + * struct my_obj *my_obj = nl_object_priv(obj); + * + * // It is absolutely essential to use nl_dump() when printing + * // any text to make sure the dumping parameters are respected. + * nl_dump(params, "Obj Integer: %d\n", my_obj->my_int); + * + * // Before we can dump the next line, make sure to prefix + * // this line correctly. + * nl_new_line(params); + * + * // You may also split a line into multiple nl_dump() calls. + * nl_dump(params, "String: %s ", my_obj->my_string); + * nl_dump(params, "String-2: %s\n", my_obj->another_string); + * } + * + * struct nl_object_ops my_ops = { + * ... + * .oo_dump[NL_DUMP_FULL] = my_obj_dump_detailed, + * }; + * @endcode + * + * @par 4) Object Attributes + * @code + * // The concept of object attributes is optional but can ease the typical + * // case of objects that have optional attributes, e.g. a route may have a + * // nexthop assigned but it is not required to. + * + * // The first step to define your object specific bitmask listing all + * // attributes + * #define MY_ATTR_FOO (1<<0) + * #define MY_ATTR_BAR (1<<1) + * + * // When assigning an optional attribute to the object, make sure + * // to mark its availability. + * my_obj->foo = 123123; + * my_obj->ce_mask |= MY_ATTR_FOO; + * + * // At any time you may use this mask to check for the availability + * // of the attribute, e.g. while dumping + * if (my_obj->ce_mask & MY_ATTR_FOO) + * nl_dump(params, "foo %d ", my_obj->foo); + * + * // One of the big advantages of this concept is that it allows for + * // standardized comparisons which make it trivial for caches to + * // identify unique objects by use of unified comparison functions. + * // In order for it to work, your object implementation must provide + * // a comparison function and define a list of attributes which + * // combined together make an object unique. + * + * static int my_obj_compare(struct nl_object *_a, struct nl_object *_b, + * uint32_t attrs, int flags) + * { + * struct my_obj *a = nl_object_priv(_a): + * struct my_obj *b = nl_object_priv(_b): + * int diff = 0; + * + * // We help ourselves in defining our own DIFF macro which will + * // call ATTR_DIFF() on both objects which will make sure to only + * // compare the attributes if required. + * #define MY_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, MY_ATTR_##ATTR, a, b, EXPR) + * + * // Call our own diff macro for each attribute to build a bitmask + * // representing the attributes which mismatch. + * diff |= MY_DIFF(FOO, a->foo != b->foo) + * diff |= MY_DIFF(BAR, strcmp(a->bar, b->bar)) + * + * return diff; + * } + * + * // In order to identify identical objects with differing attributes + * // you must specify the attributes required to uniquely identify + * // your object. Make sure to not include too many attributes, this + * // list is used when caches look for an old version of an object. + * struct nl_object_ops my_ops = { + * ... + * .oo_id_attrs = MY_ATTR_FOO, + * .oo_compare = my_obj_compare, + * }; + * @endcode + * @{ + */ + +/** + * Common Object Header + * + * This macro must be included as first member in every object + * definition to allow objects to be cached. + */ +#define NLHDR_COMMON \ + int ce_refcnt; \ + struct nl_object_ops * ce_ops; \ + struct nl_cache * ce_cache; \ + struct nl_list_head ce_list; \ + int ce_msgtype; \ + int ce_flags; \ + uint32_t ce_mask; + +struct nl_object +{ + NLHDR_COMMON +}; + + +/** + * Return true if attribute is available in both objects + * @arg A an object + * @arg B another object + * @arg ATTR attribute bit + * + * @return True if the attribute is available, otherwise false is returned. + */ +#define AVAILABLE(A, B, ATTR) (((A)->ce_mask & (B)->ce_mask) & (ATTR)) + +/** + * Return true if attribute is available in only one of both objects + * @arg A an object + * @arg B another object + * @arg ATTR attribute bit + * + * @return True if the attribute is available in only one of both objects, + * otherwise false is returned. + */ +#define AVAILABLE_MISMATCH(A, B, ATTR) (((A)->ce_mask ^ (B)->ce_mask) & (ATTR)) + +/** + * Return true if attributes mismatch + * @arg A an object + * @arg B another object + * @arg ATTR attribute bit + * @arg EXPR Comparison expression + * + * This function will check if the attribute in question is available + * in both objects, if not this will count as a mismatch. + * + * If available the function will execute the expression which must + * return true if the attributes mismatch. + * + * @return True if the attribute mismatch, or false if they match. + */ +#define ATTR_MISMATCH(A, B, ATTR, EXPR) (AVAILABLE_MISMATCH(A, B, ATTR) || \ + (AVAILABLE(A, B, ATTR) && (EXPR))) + +/** + * Return attribute bit if attribute does not match + * @arg LIST list of attributes to be compared + * @arg ATTR attribute bit + * @arg A an object + * @arg B another object + * @arg EXPR Comparison expression + * + * This function will check if the attribute in question is available + * in both objects, if not this will count as a mismatch. + * + * If available the function will execute the expression which must + * return true if the attributes mismatch. + * + * In case the attributes mismatch, the attribute is returned, otherwise + * 0 is returned. + * + * @code + * diff |= ATTR_DIFF(attrs, MY_ATTR_FOO, a, b, a->foo != b->foo); + * @endcode + */ +#define ATTR_DIFF(LIST, ATTR, A, B, EXPR) \ +({ int diff = 0; \ + if (((LIST) & (ATTR)) && ATTR_MISMATCH(A, B, ATTR, EXPR)) \ + diff = ATTR; \ + diff; }) + +/** + * Object Operations + */ +struct nl_object_ops +{ + /** + * Unique name of object type + * + * Must be in the form family/name, e.g. "route/addr" + */ + char * oo_name; + + /** Size of object including its header */ + size_t oo_size; + + /* List of attributes needed to uniquely identify the object */ + uint32_t oo_id_attrs; + + /** + * Constructor function + * + * Will be called when a new object of this type is allocated. + * Can be used to initialize members such as lists etc. + */ + void (*oo_constructor)(struct nl_object *); + + /** + * Destructor function + * + * Will be called when an object is freed. Must free all + * resources which may have been allocated as part of this + * object. + */ + void (*oo_free_data)(struct nl_object *); + + /** + * Cloning function + * + * Will be called when an object needs to be cloned. Please + * note that the generic object code will make an exact + * copy of the object first, therefore you only need to take + * care of members which require reference counting etc. + * + * May return a negative error code to abort cloning. + */ + int (*oo_clone)(struct nl_object *, struct nl_object *); + + /** + * Dumping functions + * + * Will be called when an object is dumped. The implementations + * have to use nl_dump(), nl_dump_line(), and nl_new_line() to + * dump objects. + * + * The functions must return the number of lines printed. + */ + void (*oo_dump[NL_DUMP_MAX+1])(struct nl_object *, + struct nl_dump_params *); + + /** + * Comparison function + * + * Will be called when two objects of the same type are + * compared. It takes the two objects in question, an object + * specific bitmask defining which attributes should be + * compared and flags to control the behaviour. + * + * The function must return a bitmask with the relevant bit + * set for each attribute that mismatches. + */ + int (*oo_compare)(struct nl_object *, struct nl_object *, + uint32_t, int); + + + char *(*oo_attrs2str)(int, char *, size_t); +}; + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/object.h b/libnetwork/libnl3/include/netlink/object.h new file mode 100644 index 0000000..7dc62ac --- /dev/null +++ b/libnetwork/libnl3/include/netlink/object.h @@ -0,0 +1,70 @@ +/* + * netlink/object.c Generic Cacheable Object + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_OBJECT_H_ +#define NETLINK_OBJECT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct nl_cache; +struct nl_object; +struct nl_object_ops; + +#define OBJ_CAST(ptr) ((struct nl_object *) (ptr)) + +/* General */ +extern struct nl_object * nl_object_alloc(struct nl_object_ops *); +extern int nl_object_alloc_name(const char *, + struct nl_object **); +extern void nl_object_free(struct nl_object *); +extern struct nl_object * nl_object_clone(struct nl_object *obj); +extern void nl_object_get(struct nl_object *); +extern void nl_object_put(struct nl_object *); +extern int nl_object_shared(struct nl_object *); +extern void nl_object_dump(struct nl_object *, + struct nl_dump_params *); +extern void nl_object_dump_buf(struct nl_object *, char *, size_t); +extern int nl_object_identical(struct nl_object *, + struct nl_object *); +extern uint32_t nl_object_diff(struct nl_object *, + struct nl_object *); +extern int nl_object_match_filter(struct nl_object *, + struct nl_object *); +extern char * nl_object_attrs2str(struct nl_object *, + uint32_t attrs, char *buf, + size_t); +extern char * nl_object_attr_list(struct nl_object *, + char *, size_t); + +/* Marks */ +extern void nl_object_mark(struct nl_object *); +extern void nl_object_unmark(struct nl_object *); +extern int nl_object_is_marked(struct nl_object *); + +/* Access Functions */ +extern int nl_object_get_refcnt(struct nl_object *); +extern struct nl_cache * nl_object_get_cache(struct nl_object *); +static inline void * nl_object_priv(struct nl_object *obj) +{ + return obj; +} + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/addr.h b/libnetwork/libnl3/include/netlink/route/addr.h new file mode 100644 index 0000000..56c12e7 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/addr.h @@ -0,0 +1,98 @@ +/* + * netlink/route/addr.c rtnetlink addr layer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + * Copyright (c) 2003-2006 Baruch Even , + * Mediatrix Telecom, inc. + */ + +#ifndef NETADDR_ADDR_H_ +#define NETADDR_ADDR_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct rtnl_addr; + +/* General */ +extern struct rtnl_addr *rtnl_addr_alloc(void); +extern void rtnl_addr_put(struct rtnl_addr *); + +extern int rtnl_addr_alloc_cache(struct nl_sock *, struct nl_cache **); +extern struct rtnl_addr * + rtnl_addr_get(struct nl_cache *, int, struct nl_addr *); + +extern int rtnl_addr_build_add_request(struct rtnl_addr *, int, + struct nl_msg **); +extern int rtnl_addr_add(struct nl_sock *, struct rtnl_addr *, int); + +extern int rtnl_addr_build_delete_request(struct rtnl_addr *, int, + struct nl_msg **); +extern int rtnl_addr_delete(struct nl_sock *, + struct rtnl_addr *, int); + +extern char * rtnl_addr_flags2str(int, char *, size_t); +extern int rtnl_addr_str2flags(const char *); + +extern int rtnl_addr_set_label(struct rtnl_addr *, const char *); +extern char * rtnl_addr_get_label(struct rtnl_addr *); + +extern void rtnl_addr_set_ifindex(struct rtnl_addr *, int); +extern int rtnl_addr_get_ifindex(struct rtnl_addr *); + +extern void rtnl_addr_set_link(struct rtnl_addr *, struct rtnl_link *); +extern struct rtnl_link * + rtnl_addr_get_link(struct rtnl_addr *); + +extern void rtnl_addr_set_family(struct rtnl_addr *, int); +extern int rtnl_addr_get_family(struct rtnl_addr *); + +extern void rtnl_addr_set_prefixlen(struct rtnl_addr *, int); +extern int rtnl_addr_get_prefixlen(struct rtnl_addr *); + +extern void rtnl_addr_set_scope(struct rtnl_addr *, int); +extern int rtnl_addr_get_scope(struct rtnl_addr *); + +extern void rtnl_addr_set_flags(struct rtnl_addr *, unsigned int); +extern void rtnl_addr_unset_flags(struct rtnl_addr *, unsigned int); +extern unsigned int rtnl_addr_get_flags(struct rtnl_addr *); + +extern int rtnl_addr_set_local(struct rtnl_addr *, + struct nl_addr *); +extern struct nl_addr *rtnl_addr_get_local(struct rtnl_addr *); + +extern int rtnl_addr_set_peer(struct rtnl_addr *, struct nl_addr *); +extern struct nl_addr *rtnl_addr_get_peer(struct rtnl_addr *); + +extern int rtnl_addr_set_broadcast(struct rtnl_addr *, struct nl_addr *); +extern struct nl_addr *rtnl_addr_get_broadcast(struct rtnl_addr *); + +extern int rtnl_addr_set_multicast(struct rtnl_addr *, struct nl_addr *); +extern struct nl_addr *rtnl_addr_get_multicast(struct rtnl_addr *); + +extern int rtnl_addr_set_anycast(struct rtnl_addr *, struct nl_addr *); +extern struct nl_addr *rtnl_addr_get_anycast(struct rtnl_addr *); + +extern uint32_t rtnl_addr_get_valid_lifetime(struct rtnl_addr *); +extern void rtnl_addr_set_valid_lifetime(struct rtnl_addr *, uint32_t); +extern uint32_t rtnl_addr_get_preferred_lifetime(struct rtnl_addr *); +extern void rtnl_addr_set_preferred_lifetime(struct rtnl_addr *, uint32_t); +extern uint32_t rtnl_addr_get_create_time(struct rtnl_addr *); +extern uint32_t rtnl_addr_get_last_update_time(struct rtnl_addr *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/class.h b/libnetwork/libnl3/include/netlink/route/class.h new file mode 100644 index 0000000..e73b60a --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/class.h @@ -0,0 +1,66 @@ +/* + * netlink/route/class.h Traffic Classes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +#ifndef NETLINK_CLASS_H_ +#define NETLINK_CLASS_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct rtnl_class; + +extern struct rtnl_class * + rtnl_class_alloc(void); +extern void rtnl_class_put(struct rtnl_class *); + +extern int rtnl_class_alloc_cache(struct nl_sock *, int, + struct nl_cache **); +extern struct rtnl_class * + rtnl_class_get(struct nl_cache *, int, uint32_t); + +extern struct rtnl_qdisc * + rtnl_class_leaf_qdisc(struct rtnl_class *, + struct nl_cache *); + +extern int rtnl_class_build_add_request(struct rtnl_class *, int, + struct nl_msg **); +extern int rtnl_class_add(struct nl_sock *, struct rtnl_class *, + int); + +extern int rtnl_class_build_delete_request(struct rtnl_class *, + struct nl_msg **); +extern int rtnl_class_delete(struct nl_sock *, + struct rtnl_class *); + +/* deprecated functions */ +extern void rtnl_class_foreach_child(struct rtnl_class *, + struct nl_cache *, + void (*cb)(struct nl_object *, + void *), + void *) + __attribute__((deprecated)); +extern void rtnl_class_foreach_cls(struct rtnl_class *, + struct nl_cache *, + void (*cb)(struct nl_object *, + void *), + void *) + __attribute__((deprecated)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/classifier.h b/libnetwork/libnl3/include/netlink/route/classifier.h new file mode 100644 index 0000000..647bf1e --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/classifier.h @@ -0,0 +1,51 @@ +/* + * netlink/route/classifier.h Classifiers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +#ifndef NETLINK_CLASSIFIER_H_ +#define NETLINK_CLASSIFIER_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct rtnl_cls *rtnl_cls_alloc(void); +extern void rtnl_cls_put(struct rtnl_cls *); + +extern int rtnl_cls_alloc_cache(struct nl_sock *, int, uint32_t, + struct nl_cache **); + +extern int rtnl_cls_build_add_request(struct rtnl_cls *, int, + struct nl_msg **); +extern int rtnl_cls_add(struct nl_sock *, struct rtnl_cls *, int); + +extern int rtnl_cls_build_change_request(struct rtnl_cls *, int, + struct nl_msg **); +extern int rtnl_cls_build_delete_request(struct rtnl_cls *, int, + struct nl_msg **); +extern int rtnl_cls_delete(struct nl_sock *, struct rtnl_cls *, + int); + +extern void rtnl_cls_set_prio(struct rtnl_cls *, uint16_t); +extern uint16_t rtnl_cls_get_prio(struct rtnl_cls *); + +extern void rtnl_cls_set_protocol(struct rtnl_cls *, uint16_t); +extern uint16_t rtnl_cls_get_protocol(struct rtnl_cls *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/cls/basic.h b/libnetwork/libnl3/include/netlink/route/cls/basic.h new file mode 100644 index 0000000..8b58c1e --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/cls/basic.h @@ -0,0 +1,31 @@ +/* + * netlink/route/cls/basic.h Basic Classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2010 Thomas Graf + */ + +#ifndef NETLINK_BASIC_H_ +#define NETLINK_BASIC_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void rtnl_basic_set_target(struct rtnl_cls *, uint32_t); +extern uint32_t rtnl_basic_get_target(struct rtnl_cls *); +extern void rtnl_basic_set_ematch(struct rtnl_cls *, + struct rtnl_ematch_tree *); +extern struct rtnl_ematch_tree *rtnl_basic_get_ematch(struct rtnl_cls *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/cls/cgroup.h b/libnetwork/libnl3/include/netlink/route/cls/cgroup.h new file mode 100644 index 0000000..20346ff --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/cls/cgroup.h @@ -0,0 +1,30 @@ +/* + * netlink/route/cls/cgroup.h Control Groups Classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2009-2010 Thomas Graf + */ + +#ifndef NETLINK_CLS_CGROUP_H_ +#define NETLINK_CLS_CGROUP_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void rtnl_cgroup_set_ematch(struct rtnl_cls *, + struct rtnl_ematch_tree *); +struct rtnl_ematch_tree * rtnl_cgroup_get_ematch(struct rtnl_cls *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/cls/ematch.h b/libnetwork/libnl3/include/netlink/route/cls/ematch.h new file mode 100644 index 0000000..13f9c32 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/cls/ematch.h @@ -0,0 +1,95 @@ +/* + * netlink/route/cls/ematch.h Extended Matches + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2010 Thomas Graf + */ + +#ifndef NETLINK_CLS_EMATCH_H_ +#define NETLINK_CLS_EMATCH_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* FIXME: Should be moved to the kernel header at some point */ +#define RTNL_EMATCH_PROGID 2 + +struct rtnl_ematch; +struct rtnl_ematch_tree; + +/** + * Extended Match Operations + */ +struct rtnl_ematch_ops +{ + int eo_kind; + const char * eo_name; + size_t eo_minlen; + size_t eo_datalen; + + int (*eo_parse)(struct rtnl_ematch *, void *, size_t); + void (*eo_dump)(struct rtnl_ematch *, + struct nl_dump_params *); + int (*eo_fill)(struct rtnl_ematch *, struct nl_msg *); + void (*eo_free)(struct rtnl_ematch *); + struct nl_list_head eo_list; +}; + +extern int rtnl_ematch_register(struct rtnl_ematch_ops *); +extern struct rtnl_ematch_ops * rtnl_ematch_lookup_ops(int); +extern struct rtnl_ematch_ops * rtnl_ematch_lookup_ops_by_name(const char *); + +extern struct rtnl_ematch * rtnl_ematch_alloc(void); +extern int rtnl_ematch_add_child(struct rtnl_ematch *, + struct rtnl_ematch *); +extern void rtnl_ematch_unlink(struct rtnl_ematch *); +extern void rtnl_ematch_free(struct rtnl_ematch *); + +extern void * rtnl_ematch_data(struct rtnl_ematch *); +extern void rtnl_ematch_set_flags(struct rtnl_ematch *, + uint16_t); +extern void rtnl_ematch_unset_flags(struct rtnl_ematch *, + uint16_t); +extern uint16_t rtnl_ematch_get_flags(struct rtnl_ematch *); +extern int rtnl_ematch_set_ops(struct rtnl_ematch *, + struct rtnl_ematch_ops *); +extern int rtnl_ematch_set_kind(struct rtnl_ematch *, + uint16_t); +extern int rtnl_ematch_set_name(struct rtnl_ematch *, + const char *); + +extern struct rtnl_ematch_tree *rtnl_ematch_tree_alloc(uint16_t); +extern void rtnl_ematch_tree_free(struct rtnl_ematch_tree *); +extern void rtnl_ematch_tree_add(struct rtnl_ematch_tree *, + struct rtnl_ematch *); + +extern int rtnl_ematch_parse_attr(struct nlattr *, + struct rtnl_ematch_tree **); +extern int rtnl_ematch_fill_attr(struct nl_msg *, int, + struct rtnl_ematch_tree *); +extern void rtnl_ematch_tree_dump(struct rtnl_ematch_tree *, + struct nl_dump_params *); + + +extern int rtnl_ematch_parse_expr(const char *, char **, + struct rtnl_ematch_tree **); + +extern char * rtnl_ematch_offset2txt(uint8_t, uint16_t, + char *, size_t); +extern char * rtnl_ematch_opnd2txt(uint8_t, char *, size_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/cls/ematch/cmp.h b/libnetwork/libnl3/include/netlink/route/cls/ematch/cmp.h new file mode 100644 index 0000000..308113e --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/cls/ematch/cmp.h @@ -0,0 +1,32 @@ +/* + * netlink/route/cls/ematch/cmp.h Simple Comparison + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2010 Thomas Graf + */ + +#ifndef NETLINK_CLS_EMATCH_CMP_H_ +#define NETLINK_CLS_EMATCH_CMP_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void rtnl_ematch_cmp_set(struct rtnl_ematch *, + struct tcf_em_cmp *); +extern struct tcf_em_cmp * + rtnl_ematch_cmp_get(struct rtnl_ematch *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/cls/ematch/meta.h b/libnetwork/libnl3/include/netlink/route/cls/ematch/meta.h new file mode 100644 index 0000000..2fe5899 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/cls/ematch/meta.h @@ -0,0 +1,41 @@ +/* + * netlink/route/cls/ematch/meta.h Metadata Match + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf + */ + +#ifndef NETLINK_CLS_EMATCH_META_H_ +#define NETLINK_CLS_EMATCH_META_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct rtnl_meta_value; + +extern struct rtnl_meta_value * rtnl_meta_value_alloc_int(uint64_t); +extern struct rtnl_meta_value * rtnl_meta_value_alloc_var(void *, size_t); +extern struct rtnl_meta_value * rtnl_meta_value_alloc_id(uint8_t, uint16_t, + uint8_t, uint64_t); +extern void rtnl_meta_value_put(struct rtnl_meta_value *); + +extern void rtnl_ematch_meta_set_lvalue(struct rtnl_ematch *, + struct rtnl_meta_value *); +void rtnl_ematch_meta_set_rvalue(struct rtnl_ematch *, + struct rtnl_meta_value *); +extern void rtnl_ematch_meta_set_operand(struct rtnl_ematch *, uint8_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/cls/ematch/nbyte.h b/libnetwork/libnl3/include/netlink/route/cls/ematch/nbyte.h new file mode 100644 index 0000000..014c719 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/cls/ematch/nbyte.h @@ -0,0 +1,36 @@ +/* + * netlink/route/cls/ematch/nbyte.h N-Byte Comparison + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf + */ + +#ifndef NETLINK_CLS_EMATCH_NBYTE_H_ +#define NETLINK_CLS_EMATCH_NBYTE_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void rtnl_ematch_nbyte_set_offset(struct rtnl_ematch *, + uint8_t, uint16_t); +extern uint16_t rtnl_ematch_nbyte_get_offset(struct rtnl_ematch *); +extern uint8_t rtnl_ematch_nbyte_get_layer(struct rtnl_ematch *); +extern void rtnl_ematch_nbyte_set_pattern(struct rtnl_ematch *, + uint8_t *, size_t); +extern uint8_t * rtnl_ematch_nbyte_get_pattern(struct rtnl_ematch *); +extern size_t rtnl_ematch_nbyte_get_len(struct rtnl_ematch *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/cls/ematch/text.h b/libnetwork/libnl3/include/netlink/route/cls/ematch/text.h new file mode 100644 index 0000000..e599abf --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/cls/ematch/text.h @@ -0,0 +1,42 @@ +/* + * netlink/route/cls/ematch/text.h Text Search + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf + */ + +#ifndef NETLINK_CLS_EMATCH_TEXT_H_ +#define NETLINK_CLS_EMATCH_TEXT_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void rtnl_ematch_text_set_from(struct rtnl_ematch *, + uint8_t, uint16_t); +extern uint16_t rtnl_ematch_text_get_from_offset(struct rtnl_ematch *); +extern uint8_t rtnl_ematch_text_get_from_layer(struct rtnl_ematch *); +extern void rtnl_ematch_text_set_to(struct rtnl_ematch *, + uint8_t, uint16_t); +extern uint16_t rtnl_ematch_text_get_to_offset(struct rtnl_ematch *); +extern uint8_t rtnl_ematch_text_get_to_layer(struct rtnl_ematch *); +extern void rtnl_ematch_text_set_pattern(struct rtnl_ematch *, + char *, size_t); +extern char * rtnl_ematch_text_get_pattern(struct rtnl_ematch *); +extern size_t rtnl_ematch_text_get_len(struct rtnl_ematch *); +extern void rtnl_ematch_text_set_algo(struct rtnl_ematch *, const char *); +extern char * rtnl_ematch_text_get_algo(struct rtnl_ematch *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/cls/fw.h b/libnetwork/libnl3/include/netlink/route/cls/fw.h new file mode 100644 index 0000000..39878de --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/cls/fw.h @@ -0,0 +1,29 @@ +/* + * netlink/route/cls/fw.h fw classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + * Copyright (c) 2006 Petr Gotthard + * Copyright (c) 2006 Siemens AG Oesterreich + */ + +#ifndef NETLINK_FW_H_ +#define NETLINK_FW_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern int rtnl_fw_set_classid(struct rtnl_cls *, uint32_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/cls/police.h b/libnetwork/libnl3/include/netlink/route/cls/police.h new file mode 100644 index 0000000..cd1efb0 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/cls/police.h @@ -0,0 +1,29 @@ +/* + * netlink/route/cls/police.h Policer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_CLS_POLICE_H_ +#define NETLINK_CLS_POLICE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern char * nl_police2str(int, char *, size_t); +extern int nl_str2police(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/cls/u32.h b/libnetwork/libnl3/include/netlink/route/cls/u32.h new file mode 100644 index 0000000..cf35e26 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/cls/u32.h @@ -0,0 +1,43 @@ +/* + * netlink/route/cls/u32.h u32 classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_U32_H_ +#define NETLINK_U32_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void rtnl_u32_set_handle(struct rtnl_cls *, int, int, int); +extern int rtnl_u32_set_classid(struct rtnl_cls *, uint32_t); + +extern int rtnl_u32_set_flags(struct rtnl_cls *, int); +extern int rtnl_u32_add_key(struct rtnl_cls *, uint32_t, uint32_t, + int, int); +extern int rtnl_u32_add_key_uint8(struct rtnl_cls *, uint8_t, uint8_t, + int, int); +extern int rtnl_u32_add_key_uint16(struct rtnl_cls *, uint16_t, uint16_t, + int, int); +extern int rtnl_u32_add_key_uint32(struct rtnl_cls *, uint32_t, uint32_t, + int, int); +extern int rtnl_u32_add_key_in_addr(struct rtnl_cls *, struct in_addr *, + uint8_t, int, int); +extern int rtnl_u32_add_key_in6_addr(struct rtnl_cls *, struct in6_addr *, + uint8_t, int, int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/link.h b/libnetwork/libnl3/include/netlink/route/link.h new file mode 100644 index 0000000..42ef7c8 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/link.h @@ -0,0 +1,217 @@ +/* + * netlink/route/link.h Links (Interfaces) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +#ifndef NETLINK_LINK_H_ +#define NETLINK_LINK_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @struct rtnl_link link.h "netlink/route/link.h" + * @brief Link object + * @implements nl_object + * @ingroup link + * + * @copydoc private_struct + */ +struct rtnl_link; + +/** + * @ingroup link + */ +typedef enum { + RTNL_LINK_RX_PACKETS, /*!< Packets received */ + RTNL_LINK_TX_PACKETS, /*!< Packets sent */ + RTNL_LINK_RX_BYTES, /*!< Bytes received */ + RTNL_LINK_TX_BYTES, /*!< Bytes sent */ + RTNL_LINK_RX_ERRORS, /*!< Receive errors */ + RTNL_LINK_TX_ERRORS, /*!< Send errors */ + RTNL_LINK_RX_DROPPED, /*!< Received packets dropped */ + RTNL_LINK_TX_DROPPED, /*!< Packets dropped during transmit */ + RTNL_LINK_RX_COMPRESSED, /*!< Compressed packets received */ + RTNL_LINK_TX_COMPRESSED, /*!< Compressed packets sent */ + RTNL_LINK_RX_FIFO_ERR, /*!< Receive FIFO errors */ + RTNL_LINK_TX_FIFO_ERR, /*!< Send FIFO errors */ + RTNL_LINK_RX_LEN_ERR, /*!< Length errors */ + RTNL_LINK_RX_OVER_ERR, /*!< Over errors */ + RTNL_LINK_RX_CRC_ERR, /*!< CRC errors */ + RTNL_LINK_RX_FRAME_ERR, /*!< Frame errors */ + RTNL_LINK_RX_MISSED_ERR, /*!< Missed errors */ + RTNL_LINK_TX_ABORT_ERR, /*!< Aborted errors */ + RTNL_LINK_TX_CARRIER_ERR, /*!< Carrier errors */ + RTNL_LINK_TX_HBEAT_ERR, /*!< Heartbeat errors */ + RTNL_LINK_TX_WIN_ERR, /*!< Window errors */ + RTNL_LINK_COLLISIONS, /*!< Send collisions */ + RTNL_LINK_MULTICAST, /*!< Multicast */ + RTNL_LINK_IP6_INPKTS, /*!< IPv6 SNMP InReceives */ + RTNL_LINK_IP6_INHDRERRORS, /*!< IPv6 SNMP InHdrErrors */ + RTNL_LINK_IP6_INTOOBIGERRORS, /*!< IPv6 SNMP InTooBigErrors */ + RTNL_LINK_IP6_INNOROUTES, /*!< IPv6 SNMP InNoRoutes */ + RTNL_LINK_IP6_INADDRERRORS, /*!< IPv6 SNMP InAddrErrors */ + RTNL_LINK_IP6_INUNKNOWNPROTOS, /*!< IPv6 SNMP InUnknownProtos */ + RTNL_LINK_IP6_INTRUNCATEDPKTS, /*!< IPv6 SNMP InTruncatedPkts */ + RTNL_LINK_IP6_INDISCARDS, /*!< IPv6 SNMP InDiscards */ + RTNL_LINK_IP6_INDELIVERS, /*!< IPv6 SNMP InDelivers */ + RTNL_LINK_IP6_OUTFORWDATAGRAMS, /*!< IPv6 SNMP OutForwDatagrams */ + RTNL_LINK_IP6_OUTPKTS, /*!< IPv6 SNMP OutRequests */ + RTNL_LINK_IP6_OUTDISCARDS, /*!< IPv6 SNMP OutDiscards */ + RTNL_LINK_IP6_OUTNOROUTES, /*!< IPv6 SNMP OutNoRoutes */ + RTNL_LINK_IP6_REASMTIMEOUT, /*!< IPv6 SNMP ReasmTimeout */ + RTNL_LINK_IP6_REASMREQDS, /*!< IPv6 SNMP ReasmReqds */ + RTNL_LINK_IP6_REASMOKS, /*!< IPv6 SNMP ReasmOKs */ + RTNL_LINK_IP6_REASMFAILS, /*!< IPv6 SNMP ReasmFails */ + RTNL_LINK_IP6_FRAGOKS, /*!< IPv6 SNMP FragOKs */ + RTNL_LINK_IP6_FRAGFAILS, /*!< IPv6 SNMP FragFails */ + RTNL_LINK_IP6_FRAGCREATES, /*!< IPv6 SNMP FragCreates */ + RTNL_LINK_IP6_INMCASTPKTS, /*!< IPv6 SNMP InMcastPkts */ + RTNL_LINK_IP6_OUTMCASTPKTS, /*!< IPv6 SNMP OutMcastPkts */ + RTNL_LINK_IP6_INBCASTPKTS, /*!< IPv6 SNMP InBcastPkts */ + RTNL_LINK_IP6_OUTBCASTPKTS, /*!< IPv6 SNMP OutBcastPkts */ + RTNL_LINK_IP6_INOCTETS, /*!< IPv6 SNMP InOctets */ + RTNL_LINK_IP6_OUTOCTETS, /*!< IPv6 SNMP OutOctets */ + RTNL_LINK_IP6_INMCASTOCTETS, /*!< IPv6 SNMP InMcastOctets */ + RTNL_LINK_IP6_OUTMCASTOCTETS, /*!< IPv6 SNMP OutMcastOctets */ + RTNL_LINK_IP6_INBCASTOCTETS, /*!< IPv6 SNMP InBcastOctets */ + RTNL_LINK_IP6_OUTBCASTOCTETS, /*!< IPv6 SNMP OutBcastOctets */ + RTNL_LINK_ICMP6_INMSGS, /*!< ICMPv6 SNMP InMsgs */ + RTNL_LINK_ICMP6_INERRORS, /*!< ICMPv6 SNMP InErrors */ + RTNL_LINK_ICMP6_OUTMSGS, /*!< ICMPv6 SNMP OutMsgs */ + RTNL_LINK_ICMP6_OUTERRORS, /*!< ICMPv6 SNMP OutErrors */ + __RTNL_LINK_STATS_MAX, +} rtnl_link_stat_id_t; + +#define RTNL_LINK_STATS_MAX (__RTNL_LINK_STATS_MAX - 1) + +extern struct rtnl_link *rtnl_link_alloc(void); +extern void rtnl_link_put(struct rtnl_link *); +extern void rtnl_link_free(struct rtnl_link *); + +extern int rtnl_link_alloc_cache(struct nl_sock *, int, struct nl_cache **); +extern struct rtnl_link *rtnl_link_get(struct nl_cache *, int); +extern struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *, const char *); + + +extern int rtnl_link_build_add_request(struct rtnl_link *, int, + struct nl_msg **); +extern int rtnl_link_add(struct nl_sock *, struct rtnl_link *, int); +extern int rtnl_link_build_change_request(struct rtnl_link *, + struct rtnl_link *, int, + struct nl_msg **); +extern int rtnl_link_change(struct nl_sock *, struct rtnl_link *, + struct rtnl_link *, int); + +extern int rtnl_link_build_delete_request(const struct rtnl_link *, + struct nl_msg **); +extern int rtnl_link_delete(struct nl_sock *, const struct rtnl_link *); +extern int rtnl_link_build_get_request(int, const char *, + struct nl_msg **); +extern int rtnl_link_get_kernel(struct nl_sock *, int, const char *, + struct rtnl_link **); + +/* Name <-> Index Translations */ +extern char * rtnl_link_i2name(struct nl_cache *, int, char *, size_t); +extern int rtnl_link_name2i(struct nl_cache *, const char *); + +/* Name <-> Statistic Translations */ +extern char * rtnl_link_stat2str(int, char *, size_t); +extern int rtnl_link_str2stat(const char *); + +/* Link Flags Translations */ +extern char * rtnl_link_flags2str(int, char *, size_t); +extern int rtnl_link_str2flags(const char *); + +extern char * rtnl_link_operstate2str(uint8_t, char *, size_t); +extern int rtnl_link_str2operstate(const char *); + +extern char * rtnl_link_mode2str(uint8_t, char *, size_t); +extern int rtnl_link_str2mode(const char *); + +/* Access Functions */ +extern void rtnl_link_set_qdisc(struct rtnl_link *, const char *); +extern char * rtnl_link_get_qdisc(struct rtnl_link *); + +extern void rtnl_link_set_name(struct rtnl_link *, const char *); +extern char * rtnl_link_get_name(struct rtnl_link *); + +extern void rtnl_link_set_flags(struct rtnl_link *, unsigned int); +extern void rtnl_link_unset_flags(struct rtnl_link *, unsigned int); +extern unsigned int rtnl_link_get_flags(struct rtnl_link *); + +extern void rtnl_link_set_mtu(struct rtnl_link *, unsigned int); +extern unsigned int rtnl_link_get_mtu(struct rtnl_link *); + +extern void rtnl_link_set_txqlen(struct rtnl_link *, unsigned int); +extern unsigned int rtnl_link_get_txqlen(struct rtnl_link *); + +extern void rtnl_link_set_ifindex(struct rtnl_link *, int); +extern int rtnl_link_get_ifindex(struct rtnl_link *); + +extern void rtnl_link_set_family(struct rtnl_link *, int); +extern int rtnl_link_get_family(struct rtnl_link *); + +extern void rtnl_link_set_arptype(struct rtnl_link *, unsigned int); +extern unsigned int rtnl_link_get_arptype(struct rtnl_link *); + +extern void rtnl_link_set_addr(struct rtnl_link *, struct nl_addr *); +extern struct nl_addr *rtnl_link_get_addr(struct rtnl_link *); + +extern void rtnl_link_set_broadcast(struct rtnl_link *, struct nl_addr *); +extern struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *); + +extern void rtnl_link_set_link(struct rtnl_link *, int); +extern int rtnl_link_get_link(struct rtnl_link *); + +extern void rtnl_link_set_master(struct rtnl_link *, int); +extern int rtnl_link_get_master(struct rtnl_link *); + +extern void rtnl_link_set_operstate(struct rtnl_link *, uint8_t); +extern uint8_t rtnl_link_get_operstate(struct rtnl_link *); + +extern void rtnl_link_set_linkmode(struct rtnl_link *, uint8_t); +extern uint8_t rtnl_link_get_linkmode(struct rtnl_link *); + +extern const char * rtnl_link_get_ifalias(struct rtnl_link *); +extern void rtnl_link_set_ifalias(struct rtnl_link *, const char *); + +extern int rtnl_link_get_num_vf(struct rtnl_link *, uint32_t *); + +extern uint64_t rtnl_link_get_stat(struct rtnl_link *, rtnl_link_stat_id_t); +extern int rtnl_link_set_stat(struct rtnl_link *, rtnl_link_stat_id_t, + const uint64_t); + +extern int rtnl_link_set_type(struct rtnl_link *, const char *); +extern char * rtnl_link_get_type(struct rtnl_link *); + +extern int rtnl_link_enslave_ifindex(struct nl_sock *, int, int); +extern int rtnl_link_enslave(struct nl_sock *, struct rtnl_link *, + struct rtnl_link *); +extern int rtnl_link_release_ifindex(struct nl_sock *, int); +extern int rtnl_link_release(struct nl_sock *, struct rtnl_link *); + +/* deprecated */ +extern int rtnl_link_set_info_type(struct rtnl_link *, const char *) __attribute__((deprecated)); +extern char * rtnl_link_get_info_type(struct rtnl_link *) __attribute__((deprecated)); +extern void rtnl_link_set_weight(struct rtnl_link *, unsigned int) __attribute__((deprecated)); +extern unsigned int rtnl_link_get_weight(struct rtnl_link *) __attribute__((deprecated)); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/link/api.h b/libnetwork/libnl3/include/netlink/route/link/api.h new file mode 100644 index 0000000..960d3f1 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/link/api.h @@ -0,0 +1,134 @@ +/* + * netlink/route/link/api.h Link Modules API + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2010 Thomas Graf + */ + +#ifndef NETLINK_LINK_API_H_ +#define NETLINK_LINK_API_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @ingroup link_api + * + * Available operations to modules implementing a link info type. + */ +struct rtnl_link_info_ops +{ + /** Name of link info type, must match name on kernel side */ + char * io_name; + + /** Reference count, DO NOT MODIFY */ + int io_refcnt; + + /** Called to assign an info type to a link. + * Has to allocate enough resources to hold attributes. Can + * use link->l_info to store a pointer. */ + int (*io_alloc)(struct rtnl_link *); + + /** Called to parse the link info attribute. + * Must parse the attribute and assign all values to the link. + */ + int (*io_parse)(struct rtnl_link *, + struct nlattr *, + struct nlattr *); + + /** Called when the link object is dumped. + * Must dump the info type specific attributes. */ + void (*io_dump[NL_DUMP_MAX+1])(struct rtnl_link *, + struct nl_dump_params *); + + /** Called when a link object is cloned. + * Must clone all info type specific attributes. */ + int (*io_clone)(struct rtnl_link *, struct rtnl_link *); + + /** Called when construction a link netlink message. + * Must append all info type specific attributes to the message. */ + int (*io_put_attrs)(struct nl_msg *, struct rtnl_link *); + + /** Called to release all resources previously allocated + * in either io_alloc() or io_parse(). */ + void (*io_free)(struct rtnl_link *); + + struct nl_list_head io_list; +}; + +extern struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *); +extern void rtnl_link_info_ops_put(struct rtnl_link_info_ops *); +extern int rtnl_link_register_info(struct rtnl_link_info_ops *); +extern int rtnl_link_unregister_info(struct rtnl_link_info_ops *); + + +/** + * @ingroup link_api + * + * Available operations to modules implementing a link address family. + */ +struct rtnl_link_af_ops +{ + /** The address family this operations set implements */ + const unsigned int ao_family; + + /** Number of users of this operations, DO NOT MODIFY. */ + int ao_refcnt; + + /** Validation policy for IFLA_PROTINFO attribute. This pointer + * can be set to a nla_policy structure describing the minimal + * requirements the attribute must meet. Failure of meeting these + * requirements will result in a parsing error. */ + const struct nla_policy *ao_protinfo_policy; + + /** Called after address family has been assigned to link. Must + * allocate data buffer to hold address family specific data and + * store it in link->l_af_data. */ + void * (*ao_alloc)(struct rtnl_link *); + + /** Called when the link is cloned, must allocate a clone of the + * address family specific buffer and return it. */ + void * (*ao_clone)(struct rtnl_link *, void *); + + /** Called when the link gets freed. Must free all allocated data */ + void (*ao_free)(struct rtnl_link *, void *); + + /** Called if a IFLA_PROTINFO attribute needs to be parsed. Typically + * stores the parsed data in the address family specific buffer. */ + int (*ao_parse_protinfo)(struct rtnl_link *, + struct nlattr *, void *); + + /** Called if a IFLA_AF_SPEC attribute needs to be parsed. Typically + * stores the parsed data in the address family specific buffer. */ + int (*ao_parse_af)(struct rtnl_link *, + struct nlattr *, void *); + + /** Called if a link message is sent to the kernel. Must append the + * link address family specific attributes to the message. */ + int (*ao_fill_af)(struct rtnl_link *, + struct nl_msg *msg, void *); + + /** Dump address family specific link attributes */ + void (*ao_dump[NL_DUMP_MAX+1])(struct rtnl_link *, + struct nl_dump_params *, + void *); +}; + +extern struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(unsigned int); +extern void rtnl_link_af_ops_put(struct rtnl_link_af_ops *); +extern void * rtnl_link_af_alloc(struct rtnl_link *, + const struct rtnl_link_af_ops *); +extern void * rtnl_link_af_data(const struct rtnl_link *, + const struct rtnl_link_af_ops *); +extern int rtnl_link_af_register(struct rtnl_link_af_ops *); +extern int rtnl_link_af_unregister(struct rtnl_link_af_ops *); + + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/link/bonding.h b/libnetwork/libnl3/include/netlink/route/link/bonding.h new file mode 100644 index 0000000..78ee6bd --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/link/bonding.h @@ -0,0 +1,37 @@ +/* + * netlink/route/link/bonding.h Bonding Interface + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2011 Thomas Graf + */ + +#ifndef NETLINK_LINK_BONDING_H_ +#define NETLINK_LINK_BONDING_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern int rtnl_link_bond_add(struct nl_sock *, const char *, + struct rtnl_link *); + +extern int rtnl_link_bond_enslave_ifindex(struct nl_sock *, int, int); +extern int rtnl_link_bond_enslave(struct nl_sock *, struct rtnl_link *, + struct rtnl_link *); + +extern int rtnl_link_bond_release_ifindex(struct nl_sock *, int); +extern int rtnl_link_bond_release(struct nl_sock *, struct rtnl_link *); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/libnetwork/libnl3/include/netlink/route/link/inet.h b/libnetwork/libnl3/include/netlink/route/link/inet.h new file mode 100644 index 0000000..66419e3 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/link/inet.h @@ -0,0 +1,29 @@ +/* + * netlink/route/link/inet.h INET Link Module + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf + */ + +#ifndef NETLINK_LINK_INET_H_ +#define NETLINK_LINK_INET_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char * rtnl_link_inet_devconf2str(int, char *, size_t); +extern int rtnl_link_inet_str2devconf(const char *); + +extern int rtnl_link_inet_get_conf(struct rtnl_link *, + const unsigned int, uint32_t *); +extern int rtnl_link_inet_set_conf(struct rtnl_link *, + const unsigned int, uint32_t); + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/link/info-api.h b/libnetwork/libnl3/include/netlink/route/link/info-api.h new file mode 100644 index 0000000..4750e18 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/link/info-api.h @@ -0,0 +1,20 @@ +/* + * netlink/route/link/info-api.h Link Info API + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2010 Thomas Graf + */ + +#ifndef NETLINK_LINK_INFO_API_H_ +#define NETLINK_LINK_INFO_API_H_ + +#warning " is obsolete and may be removed in the future." +#warning "include instead. + +#include + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/link/vlan.h b/libnetwork/libnl3/include/netlink/route/link/vlan.h new file mode 100644 index 0000000..42768b6 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/link/vlan.h @@ -0,0 +1,57 @@ +/* + * netlink/route/link/vlan.h VLAN interface + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_LINK_VLAN_H_ +#define NETLINK_LINK_VLAN_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct vlan_map +{ + uint32_t vm_from; + uint32_t vm_to; +}; + +#define VLAN_PRIO_MAX 7 + +extern int rtnl_link_is_vlan(struct rtnl_link *); + +extern char * rtnl_link_vlan_flags2str(int, char *, size_t); +extern int rtnl_link_vlan_str2flags(const char *); + +extern int rtnl_link_vlan_set_id(struct rtnl_link *, uint16_t); +extern int rtnl_link_vlan_get_id(struct rtnl_link *); + +extern int rtnl_link_vlan_set_flags(struct rtnl_link *, + unsigned int); +extern int rtnl_link_vlan_unset_flags(struct rtnl_link *, + unsigned int); +extern int rtnl_link_vlan_get_flags(struct rtnl_link *); + +extern int rtnl_link_vlan_set_ingress_map(struct rtnl_link *, + int, uint32_t); +extern uint32_t * rtnl_link_vlan_get_ingress_map(struct rtnl_link *); + +extern int rtnl_link_vlan_set_egress_map(struct rtnl_link *, + uint32_t, int); +extern struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *, + int *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/neighbour.h b/libnetwork/libnl3/include/netlink/route/neighbour.h new file mode 100644 index 0000000..698539a --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/neighbour.h @@ -0,0 +1,79 @@ +/* + * netlink/route/neighbour.h Neighbours + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_NEIGHBOUR_H_ +#define NETLINK_NEIGHBOUR_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct rtnl_neigh; + +extern struct rtnl_neigh *rtnl_neigh_alloc(void); +extern void rtnl_neigh_put(struct rtnl_neigh *); + +extern int rtnl_neigh_alloc_cache(struct nl_sock *, struct nl_cache **); +extern struct rtnl_neigh *rtnl_neigh_get(struct nl_cache *, int, + struct nl_addr *); + +extern char * rtnl_neigh_state2str(int, char *, size_t); +extern int rtnl_neigh_str2state(const char *); + +extern char * rtnl_neigh_flags2str(int, char *, size_t); +extern int rtnl_neigh_str2flag(const char *); + +extern int rtnl_neigh_add(struct nl_sock *, struct rtnl_neigh *, int); +extern int rtnl_neigh_build_add_request(struct rtnl_neigh *, int, + struct nl_msg **); + +extern int rtnl_neigh_delete(struct nl_sock *, struct rtnl_neigh *, int); +extern int rtnl_neigh_build_delete_request(struct rtnl_neigh *, int, + struct nl_msg **); + +extern void rtnl_neigh_set_state(struct rtnl_neigh *, int); +extern int rtnl_neigh_get_state(struct rtnl_neigh *); +extern void rtnl_neigh_unset_state(struct rtnl_neigh *, + int); + +extern void rtnl_neigh_set_flags(struct rtnl_neigh *, + unsigned int); +extern void rtnl_neigh_unset_flags(struct rtnl_neigh *, + unsigned int); +extern unsigned int rtnl_neigh_get_flags(struct rtnl_neigh *); + +extern void rtnl_neigh_set_ifindex(struct rtnl_neigh *, + int); +extern int rtnl_neigh_get_ifindex(struct rtnl_neigh *); + +extern void rtnl_neigh_set_lladdr(struct rtnl_neigh *, + struct nl_addr *); +extern struct nl_addr * rtnl_neigh_get_lladdr(struct rtnl_neigh *); + +extern int rtnl_neigh_set_dst(struct rtnl_neigh *, + struct nl_addr *); +extern struct nl_addr * rtnl_neigh_get_dst(struct rtnl_neigh *); + +extern void rtnl_neigh_set_type(struct rtnl_neigh *, int); +extern int rtnl_neigh_get_type(struct rtnl_neigh *); + +extern void rtnl_neigh_set_family(struct rtnl_neigh *, int); +extern int rtnl_neigh_get_family(struct rtnl_neigh *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/neightbl.h b/libnetwork/libnl3/include/netlink/route/neightbl.h new file mode 100644 index 0000000..412c3e9 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/neightbl.h @@ -0,0 +1,65 @@ +/* + * netlink/route/neightbl.h Neighbour Tables + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_NEIGHTBL_H_ +#define NETLINK_NEIGHTBL_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct rtnl_neightbl; + +extern struct rtnl_neightbl *rtnl_neightbl_alloc(void); +extern void rtnl_neightbl_put(struct rtnl_neightbl *); +extern void rtnl_neightbl_free(struct rtnl_neightbl *); +extern int rtnl_neightbl_alloc_cache(struct nl_sock *, struct nl_cache **); +extern struct rtnl_neightbl *rtnl_neightbl_get(struct nl_cache *, + const char *, int); +extern void rtnl_neightbl_dump(struct rtnl_neightbl *, FILE *, + struct nl_dump_params *); + +extern int rtnl_neightbl_build_change_request(struct rtnl_neightbl *, + struct rtnl_neightbl *, + struct nl_msg **); +extern int rtnl_neightbl_change(struct nl_sock *, struct rtnl_neightbl *, + struct rtnl_neightbl *); + +extern void rtnl_neightbl_set_family(struct rtnl_neightbl *, int); +extern void rtnl_neightbl_set_gc_tresh1(struct rtnl_neightbl *, int); +extern void rtnl_neightbl_set_gc_tresh2(struct rtnl_neightbl *, int); +extern void rtnl_neightbl_set_gc_tresh3(struct rtnl_neightbl *, int); +extern void rtnl_neightbl_set_name(struct rtnl_neightbl *, const char *); +extern void rtnl_neightbl_set_dev(struct rtnl_neightbl *, int); +extern void rtnl_neightbl_set_queue_len(struct rtnl_neightbl *, int); +extern void rtnl_neightbl_set_proxy_queue_len(struct rtnl_neightbl *, int); +extern void rtnl_neightbl_set_app_probes(struct rtnl_neightbl *, int); +extern void rtnl_neightbl_set_ucast_probes(struct rtnl_neightbl *, int); +extern void rtnl_neightbl_set_mcast_probes(struct rtnl_neightbl *, int); +extern void rtnl_neightbl_set_base_reachable_time(struct rtnl_neightbl *, + uint64_t); +extern void rtnl_neightbl_set_retrans_time(struct rtnl_neightbl *, uint64_t); +extern void rtnl_neightbl_set_gc_stale_time(struct rtnl_neightbl *, uint64_t); +extern void rtnl_neightbl_set_delay_probe_time(struct rtnl_neightbl *, + uint64_t); +extern void rtnl_neightbl_set_anycast_delay(struct rtnl_neightbl *, uint64_t); +extern void rtnl_neightbl_set_proxy_delay(struct rtnl_neightbl *, uint64_t); +extern void rtnl_neightbl_set_locktime(struct rtnl_neightbl *, uint64_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/nexthop.h b/libnetwork/libnl3/include/netlink/route/nexthop.h new file mode 100644 index 0000000..2aa44dc --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/nexthop.h @@ -0,0 +1,65 @@ +/* + * netlink/route/nexthop.h Routing Nexthop + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_ROUTE_NEXTHOP_H_ +#define NETLINK_ROUTE_NEXTHOP_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct rtnl_nexthop; + +enum { + NH_DUMP_FROM_ONELINE = -2, + NH_DUMP_FROM_DETAILS = -1, + NH_DUMP_FROM_ENV = 0, + /* > 0 reserved for nexthop index */ +}; + +extern struct rtnl_nexthop * rtnl_route_nh_alloc(void); +extern struct rtnl_nexthop * rtnl_route_nh_clone(struct rtnl_nexthop *); +extern void rtnl_route_nh_free(struct rtnl_nexthop *); + +extern int rtnl_route_nh_compare(struct rtnl_nexthop *, + struct rtnl_nexthop *, + uint32_t, int); + +extern void rtnl_route_nh_dump(struct rtnl_nexthop *, + struct nl_dump_params *); + +extern void rtnl_route_nh_set_weight(struct rtnl_nexthop *, uint8_t); +extern uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *); +extern void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *, int); +extern int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *); +extern void rtnl_route_nh_set_gateway(struct rtnl_nexthop *, + struct nl_addr *); +extern struct nl_addr * rtnl_route_nh_get_gateway(struct rtnl_nexthop *); +extern void rtnl_route_nh_set_flags(struct rtnl_nexthop *, + unsigned int); +extern void rtnl_route_nh_unset_flags(struct rtnl_nexthop *, + unsigned int); +extern unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *); +extern void rtnl_route_nh_set_realms(struct rtnl_nexthop *, + uint32_t); +extern uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *); + +extern char * rtnl_route_nh_flags2str(int, char *, size_t); +extern int rtnl_route_nh_str2flags(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/pktloc.h b/libnetwork/libnl3/include/netlink/route/pktloc.h new file mode 100644 index 0000000..c3768ce --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/pktloc.h @@ -0,0 +1,49 @@ +/* + * netlink/route/pktloc.h Packet Location Aliasing + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf + */ + +#ifndef NETLINK_PKTLOC_H_ +#define NETLINK_PKTLOC_H_ + +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct rtnl_pktloc +{ + char * name; + uint8_t layer; + uint8_t shift; + uint16_t offset; + uint16_t align; + uint32_t mask; + uint32_t refcnt; + + struct nl_list_head list; +}; + +extern int rtnl_pktloc_lookup(const char *, struct rtnl_pktloc **); +extern struct rtnl_pktloc *rtnl_pktloc_alloc(void); +extern void rtnl_pktloc_put(struct rtnl_pktloc *); +extern int rtnl_pktloc_add(struct rtnl_pktloc *); +extern void rtnl_pktloc_foreach(void (*cb)(struct rtnl_pktloc *, void *), + void *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/qdisc.h b/libnetwork/libnl3/include/netlink/route/qdisc.h new file mode 100644 index 0000000..10b85c5 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/qdisc.h @@ -0,0 +1,73 @@ +/* + * netlink/route/qdisc.h Queueing Disciplines + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +#ifndef NETLINK_QDISC_H_ +#define NETLINK_QDISC_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct rtnl_qdisc; + +extern struct rtnl_qdisc * + rtnl_qdisc_alloc(void); +extern void rtnl_qdisc_put(struct rtnl_qdisc *); + +extern int rtnl_qdisc_alloc_cache(struct nl_sock *, struct nl_cache **); + +extern struct rtnl_qdisc * + rtnl_qdisc_get(struct nl_cache *, int, uint32_t); + +extern struct rtnl_qdisc * + rtnl_qdisc_get_by_parent(struct nl_cache *, int, uint32_t); + +extern int rtnl_qdisc_build_add_request(struct rtnl_qdisc *, int, + struct nl_msg **); +extern int rtnl_qdisc_add(struct nl_sock *, struct rtnl_qdisc *, int); + +extern int rtnl_qdisc_build_update_request(struct rtnl_qdisc *, + struct rtnl_qdisc *, + int, struct nl_msg **); + +extern int rtnl_qdisc_update(struct nl_sock *, struct rtnl_qdisc *, + struct rtnl_qdisc *, int); + +extern int rtnl_qdisc_build_delete_request(struct rtnl_qdisc *, + struct nl_msg **); +extern int rtnl_qdisc_delete(struct nl_sock *, struct rtnl_qdisc *); + +/* Deprecated functions */ +extern void rtnl_qdisc_foreach_child(struct rtnl_qdisc *, struct nl_cache *, + void (*cb)(struct nl_object *, void *), + void *) __attribute__ ((deprecated)); + +extern void rtnl_qdisc_foreach_cls(struct rtnl_qdisc *, struct nl_cache *, + void (*cb)(struct nl_object *, void *), + void *) __attribute__ ((deprecated)); + +extern int rtnl_qdisc_build_change_request(struct rtnl_qdisc *, + struct rtnl_qdisc *, + struct nl_msg **) + __attribute__ ((deprecated)); + +extern int rtnl_qdisc_change(struct nl_sock *, struct rtnl_qdisc *, + struct rtnl_qdisc *) __attribute__ ((deprecated)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/cbq.h b/libnetwork/libnl3/include/netlink/route/qdisc/cbq.h new file mode 100644 index 0000000..3dbdd2d --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/qdisc/cbq.h @@ -0,0 +1,30 @@ +/* + * netlink/route/sch/cbq.h Class Based Queueing + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_CBQ_H_ +#define NETLINK_CBQ_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern char * nl_ovl_strategy2str(int, char *, size_t); +extern int nl_str2ovl_strategy(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/dsmark.h b/libnetwork/libnl3/include/netlink/route/qdisc/dsmark.h new file mode 100644 index 0000000..de65496 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/qdisc/dsmark.h @@ -0,0 +1,41 @@ +/* + * netlink/route/sch/dsmark.h DSMARK + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_DSMARK_H_ +#define NETLINK_DSMARK_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern int rtnl_class_dsmark_set_bmask(struct rtnl_class *, uint8_t); +extern int rtnl_class_dsmark_get_bmask(struct rtnl_class *); + +extern int rtnl_class_dsmark_set_value(struct rtnl_class *, uint8_t); +extern int rtnl_class_dsmark_get_value(struct rtnl_class *); + +extern int rtnl_qdisc_dsmark_set_indices(struct rtnl_qdisc *, uint16_t); +extern int rtnl_qdisc_dsmark_get_indices(struct rtnl_qdisc *); + +extern int rtnl_qdisc_dsmark_set_default_index(struct rtnl_qdisc *, + uint16_t); +extern int rtnl_qdisc_dsmark_get_default_index(struct rtnl_qdisc *); + +extern int rtnl_qdisc_dsmark_set_set_tc_index(struct rtnl_qdisc *, int); +extern int rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/fifo.h b/libnetwork/libnl3/include/netlink/route/qdisc/fifo.h new file mode 100644 index 0000000..c18dd79 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/qdisc/fifo.h @@ -0,0 +1,28 @@ +/* + * netlink/route/sch/fifo.c FIFO Qdisc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_FIFO_H_ +#define NETLINK_FIFO_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern int rtnl_qdisc_fifo_set_limit(struct rtnl_qdisc *, int); +extern int rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/htb.h b/libnetwork/libnl3/include/netlink/route/qdisc/htb.h new file mode 100644 index 0000000..af0287d --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/qdisc/htb.h @@ -0,0 +1,47 @@ +/* + * netlink/route/sch/htb.h HTB Qdisc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + * Copyright (c) 2005 Petr Gotthard + * Copyright (c) 2005 Siemens AG Oesterreich + */ + +#ifndef NETLINK_HTB_H_ +#define NETLINK_HTB_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t rtnl_htb_get_rate2quantum(struct rtnl_qdisc *); +extern int rtnl_htb_set_rate2quantum(struct rtnl_qdisc *, uint32_t); +extern uint32_t rtnl_htb_get_defcls(struct rtnl_qdisc *); +extern int rtnl_htb_set_defcls(struct rtnl_qdisc *, uint32_t); + +extern uint32_t rtnl_htb_get_prio(struct rtnl_class *); +extern int rtnl_htb_set_prio(struct rtnl_class *, uint32_t); +extern uint32_t rtnl_htb_get_rate(struct rtnl_class *); +extern int rtnl_htb_set_rate(struct rtnl_class *, uint32_t); +extern uint32_t rtnl_htb_get_ceil(struct rtnl_class *); +extern int rtnl_htb_set_ceil(struct rtnl_class *, uint32_t); +extern uint32_t rtnl_htb_get_rbuffer(struct rtnl_class *); +extern int rtnl_htb_set_rbuffer(struct rtnl_class *, uint32_t); +extern uint32_t rtnl_htb_get_cbuffer(struct rtnl_class *); +extern int rtnl_htb_set_cbuffer(struct rtnl_class *, uint32_t); +extern uint32_t rtnl_htb_get_quantum(struct rtnl_class *); +extern int rtnl_htb_set_quantum(struct rtnl_class *, uint32_t); +extern int rtnl_htb_get_level(struct rtnl_class *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/netem.h b/libnetwork/libnl3/include/netlink/route/qdisc/netem.h new file mode 100644 index 0000000..ce56ee7 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/qdisc/netem.h @@ -0,0 +1,75 @@ +/* + * netlink/route/sch/netem.h Network Emulator Qdisc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_NETEM_H_ +#define NETLINK_NETEM_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void rtnl_netem_set_limit(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_limit(struct rtnl_qdisc *); + +/* Packet Re-ordering */ +extern void rtnl_netem_set_gap(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_gap(struct rtnl_qdisc *); + +extern void rtnl_netem_set_reorder_probability(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *); + +extern void rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *); + +/* Corruption */ +extern void rtnl_netem_set_corruption_probability(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *); + +extern void rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *); + +/* Packet Loss */ +extern void rtnl_netem_set_loss(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_loss(struct rtnl_qdisc *); + +extern void rtnl_netem_set_loss_correlation(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *); + +/* Packet Duplication */ +extern void rtnl_netem_set_duplicate(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_duplicate(struct rtnl_qdisc *); + +extern void rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *); + +/* Packet Delay */ +extern void rtnl_netem_set_delay(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_delay(struct rtnl_qdisc *); + +extern void rtnl_netem_set_jitter(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_jitter(struct rtnl_qdisc *); + +extern void rtnl_netem_set_delay_correlation(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *); + +/* Delay Distribution */ +#define MAXDIST 65536 +extern int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *, const char *); +extern int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *); +extern int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *, int16_t **); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/prio.h b/libnetwork/libnl3/include/netlink/route/qdisc/prio.h new file mode 100644 index 0000000..f6fdc86 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/qdisc/prio.h @@ -0,0 +1,53 @@ +/* + * netlink/route/sch/prio.c PRIO Qdisc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +#ifndef NETLINK_PRIO_H_ +#define NETLINK_PRIO_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Default Values + * @{ + */ + +/** + * Default number of bands. + * @ingroup prio + */ +#define QDISC_PRIO_DEFAULT_BANDS 3 + +/** + * Default priority mapping. + * @ingroup prio + */ +#define QDISC_PRIO_DEFAULT_PRIOMAP \ + { 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 } + +/** @} */ + +extern void rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *, int); +extern int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *); +extern int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *, uint8_t[], int); +extern uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *); + +extern char * rtnl_prio2str(int, char *, size_t); +extern int rtnl_str2prio(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/red.h b/libnetwork/libnl3/include/netlink/route/qdisc/red.h new file mode 100644 index 0000000..a4e8642 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/qdisc/red.h @@ -0,0 +1,17 @@ +/* + * netlink/route/sch/red.h RED Qdisc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_RED_H_ +#define NETLINK_RED_H_ + +#include + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/sfq.h b/libnetwork/libnl3/include/netlink/route/qdisc/sfq.h new file mode 100644 index 0000000..7cc0b3e --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/qdisc/sfq.h @@ -0,0 +1,36 @@ +/* + * netlink/route/sch/sfq.c SFQ Qdisc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +#ifndef NETLINK_SFQ_H_ +#define NETLINK_SFQ_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void rtnl_sfq_set_quantum(struct rtnl_qdisc *, int); +extern int rtnl_sfq_get_quantum(struct rtnl_qdisc *); + +extern void rtnl_sfq_set_limit(struct rtnl_qdisc *, int); +extern int rtnl_sfq_get_limit(struct rtnl_qdisc *); + +extern void rtnl_sfq_set_perturb(struct rtnl_qdisc *, int); +extern int rtnl_sfq_get_perturb(struct rtnl_qdisc *); + +extern int rtnl_sfq_get_divisor(struct rtnl_qdisc *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/qdisc/tbf.h b/libnetwork/libnl3/include/netlink/route/qdisc/tbf.h new file mode 100644 index 0000000..8a2144a --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/qdisc/tbf.h @@ -0,0 +1,40 @@ +/* + * netlink/route/sch/tbf.h TBF Qdisc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +#ifndef NETLINK_TBF_H_ +#define NETLINK_TBF_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *, int); +extern int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *, int); +extern int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *); + +extern void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *, int, int, int); +extern int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *); +extern int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *); +extern int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *); + +extern int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *, int, int, int); +extern int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *); +extern int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *); +extern int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/route.h b/libnetwork/libnl3/include/netlink/route/route.h new file mode 100644 index 0000000..5729cd7 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/route.h @@ -0,0 +1,124 @@ +/* + * netlink/route/route.h Routes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_ROUTE_H_ +#define NETLINK_ROUTE_H_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* flags */ +#define ROUTE_CACHE_CONTENT 1 + +struct rtnl_route; + +struct rtnl_rtcacheinfo +{ + uint32_t rtci_clntref; + uint32_t rtci_last_use; + uint32_t rtci_expires; + int32_t rtci_error; + uint32_t rtci_used; + uint32_t rtci_id; + uint32_t rtci_ts; + uint32_t rtci_tsage; +}; + +extern struct nl_object_ops route_obj_ops; + +extern struct rtnl_route * rtnl_route_alloc(void); +extern void rtnl_route_put(struct rtnl_route *); +extern int rtnl_route_alloc_cache(struct nl_sock *, int, int, + struct nl_cache **); + +extern void rtnl_route_get(struct rtnl_route *); +extern void rtnl_route_put(struct rtnl_route *); + +extern int rtnl_route_parse(struct nlmsghdr *, struct rtnl_route **); +extern int rtnl_route_build_msg(struct nl_msg *, struct rtnl_route *); + +extern int rtnl_route_build_add_request(struct rtnl_route *, int, + struct nl_msg **); +extern int rtnl_route_add(struct nl_sock *, struct rtnl_route *, int); +extern int rtnl_route_build_del_request(struct rtnl_route *, int, + struct nl_msg **); +extern int rtnl_route_delete(struct nl_sock *, struct rtnl_route *, int); + +extern void rtnl_route_set_table(struct rtnl_route *, uint32_t); +extern uint32_t rtnl_route_get_table(struct rtnl_route *); +extern void rtnl_route_set_scope(struct rtnl_route *, uint8_t); +extern uint8_t rtnl_route_get_scope(struct rtnl_route *); +extern void rtnl_route_set_tos(struct rtnl_route *, uint8_t); +extern uint8_t rtnl_route_get_tos(struct rtnl_route *); +extern void rtnl_route_set_protocol(struct rtnl_route *, uint8_t); +extern uint8_t rtnl_route_get_protocol(struct rtnl_route *); +extern void rtnl_route_set_priority(struct rtnl_route *, uint32_t); +extern uint32_t rtnl_route_get_priority(struct rtnl_route *); +extern int rtnl_route_set_family(struct rtnl_route *, uint8_t); +extern uint8_t rtnl_route_get_family(struct rtnl_route *); +extern int rtnl_route_set_type(struct rtnl_route *, uint8_t); +extern uint8_t rtnl_route_get_type(struct rtnl_route *); +extern void rtnl_route_set_flags(struct rtnl_route *, uint32_t); +extern void rtnl_route_unset_flags(struct rtnl_route *, uint32_t); +extern uint32_t rtnl_route_get_flags(struct rtnl_route *); +extern int rtnl_route_set_metric(struct rtnl_route *, int, unsigned int); +extern int rtnl_route_unset_metric(struct rtnl_route *, int); +extern int rtnl_route_get_metric(struct rtnl_route *, int, uint32_t *); +extern int rtnl_route_set_dst(struct rtnl_route *, struct nl_addr *); +extern struct nl_addr *rtnl_route_get_dst(struct rtnl_route *); +extern int rtnl_route_set_src(struct rtnl_route *, struct nl_addr *); +extern struct nl_addr *rtnl_route_get_src(struct rtnl_route *); +extern int rtnl_route_set_pref_src(struct rtnl_route *, struct nl_addr *); +extern struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *); +extern void rtnl_route_set_iif(struct rtnl_route *, int); +extern int rtnl_route_get_iif(struct rtnl_route *); +extern int rtnl_route_get_src_len(struct rtnl_route *); + +extern void rtnl_route_add_nexthop(struct rtnl_route *, + struct rtnl_nexthop *); +extern void rtnl_route_remove_nexthop(struct rtnl_route *, + struct rtnl_nexthop *); +extern struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *); +extern int rtnl_route_get_nnexthops(struct rtnl_route *); + +extern void rtnl_route_foreach_nexthop(struct rtnl_route *r, + void (*cb)(struct rtnl_nexthop *, void *), + void *arg); + +extern struct rtnl_nexthop * rtnl_route_nexthop_n(struct rtnl_route *r, int n); + +extern int rtnl_route_guess_scope(struct rtnl_route *); + +extern char * rtnl_route_table2str(int, char *, size_t); +extern int rtnl_route_str2table(const char *); +extern int rtnl_route_read_table_names(const char *); + +extern char * rtnl_route_proto2str(int, char *, size_t); +extern int rtnl_route_str2proto(const char *); +extern int rtnl_route_read_protocol_names(const char *); + +extern char * rtnl_route_metric2str(int, char *, size_t); +extern int rtnl_route_str2metric(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/rtnl.h b/libnetwork/libnl3/include/netlink/route/rtnl.h new file mode 100644 index 0000000..f551a5d --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/rtnl.h @@ -0,0 +1,69 @@ +/* + * netlink/route/rtnl.h Routing Netlink + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_RTNL_H_ +#define NETLINK_RTNL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Realms + * @{ + */ + +/** + * Mask specying the size of each realm part + * @ingroup rtnl + */ +#define RTNL_REALM_MASK (0xFFFF) + +/** + * Extract FROM realm from a realms field + */ +#define RTNL_REALM_FROM(realm) ((realm) >> 16) + +/** + * Extract TO realm from a realms field + */ +#define RTNL_REALM_TO(realm) ((realm) & RTNL_REALM_MASK) + +/** + * Build a realms field + */ +#define RTNL_MAKE_REALM(from, to) \ + ((RTNL_REALM_TO(from) << 16) & RTNL_REALM_TO(to)) + +/** @} */ + + +/* General */ +extern int nl_rtgen_request(struct nl_sock *, int, int, int); + +/* Routing Type Translations */ +extern char * nl_rtntype2str(int, char *, size_t); +extern int nl_str2rtntype(const char *); + +/* Scope Translations */ +extern char * rtnl_scope2str(int, char *, size_t); +extern int rtnl_str2scope(const char *); + +/* Realms Translations */ +extern char * rtnl_realms2str(uint32_t, char *, size_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/rule.h b/libnetwork/libnl3/include/netlink/route/rule.h new file mode 100644 index 0000000..760b782 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/rule.h @@ -0,0 +1,75 @@ +/* + * netlink/route/rule.h Rules + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2010 Thomas Graf + */ + +#ifndef NETLINK_RULE_H_ +#define NETLINK_RULE_H_ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct rtnl_rule; + +/* General */ +extern struct rtnl_rule * rtnl_rule_alloc(void); +extern void rtnl_rule_put(struct rtnl_rule *); + +extern int rtnl_rule_alloc_cache(struct nl_sock *, int, + struct nl_cache **); +extern void rtnl_rule_dump(struct rtnl_rule *, FILE *, struct nl_dump_params *); + +extern int rtnl_rule_build_add_request(struct rtnl_rule *, int, + struct nl_msg **); +extern int rtnl_rule_add(struct nl_sock *, struct rtnl_rule *, int); +extern int rtnl_rule_build_delete_request(struct rtnl_rule *, int, + struct nl_msg **); +extern int rtnl_rule_delete(struct nl_sock *, struct rtnl_rule *, int); + + +/* attribute modification */ +extern void rtnl_rule_set_family(struct rtnl_rule *, int); +extern int rtnl_rule_get_family(struct rtnl_rule *); +extern void rtnl_rule_set_prio(struct rtnl_rule *, uint32_t); +extern uint32_t rtnl_rule_get_prio(struct rtnl_rule *); +extern void rtnl_rule_set_mark(struct rtnl_rule *, uint32_t); +extern uint32_t rtnl_rule_get_mark(struct rtnl_rule *); +extern void rtnl_rule_set_mask(struct rtnl_rule *, uint32_t); +extern uint32_t rtnl_rule_get_mask(struct rtnl_rule *); +extern void rtnl_rule_set_table(struct rtnl_rule *, uint32_t); +extern uint32_t rtnl_rule_get_table(struct rtnl_rule *); +extern void rtnl_rule_set_dsfield(struct rtnl_rule *, uint8_t); +extern uint8_t rtnl_rule_get_dsfield(struct rtnl_rule *); +extern int rtnl_rule_set_src(struct rtnl_rule *, struct nl_addr *); +extern struct nl_addr * rtnl_rule_get_src(struct rtnl_rule *); +extern int rtnl_rule_set_dst(struct rtnl_rule *, struct nl_addr *); +extern struct nl_addr * rtnl_rule_get_dst(struct rtnl_rule *); +extern void rtnl_rule_set_action(struct rtnl_rule *, uint8_t); +extern uint8_t rtnl_rule_get_action(struct rtnl_rule *); +extern int rtnl_rule_set_iif(struct rtnl_rule *, const char *); +extern char * rtnl_rule_get_iif(struct rtnl_rule *); +extern int rtnl_rule_set_oif(struct rtnl_rule *, const char *); +extern char * rtnl_rule_get_oif(struct rtnl_rule *); +extern void rtnl_rule_set_realms(struct rtnl_rule *, uint32_t); +extern uint32_t rtnl_rule_get_realms(struct rtnl_rule *); +extern void rtnl_rule_set_goto(struct rtnl_rule *, uint32_t); +extern uint32_t rtnl_rule_get_goto(struct rtnl_rule *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/tc-api.h b/libnetwork/libnl3/include/netlink/route/tc-api.h new file mode 100644 index 0000000..d89408f --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/tc-api.h @@ -0,0 +1,143 @@ +/* + * netlink/route/tc-api.h Traffic Control API + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2011 Thomas Graf + */ + +#ifndef NETLINK_TC_API_H_ +#define NETLINK_TC_API_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum rtnl_tc_type { + RTNL_TC_TYPE_QDISC, + RTNL_TC_TYPE_CLASS, + RTNL_TC_TYPE_CLS, + __RTNL_TC_TYPE_MAX, +}; + +#define RTNL_TC_TYPE_MAX (__RTNL_TC_TYPE_MAX - 1) + +/** + * Traffic control object operations + * @ingroup tc + * + * This structure holds function pointers and settings implementing + * the features of each traffic control object implementation. + */ +struct rtnl_tc_ops +{ + /** + * Name of traffic control module + */ + char *to_kind; + + /** + * Type of traffic control object + */ + enum rtnl_tc_type to_type; + + + /** + * Size of private data + */ + size_t to_size; + + /** + * Dump callbacks + */ + void (*to_dump[NL_DUMP_MAX+1])(struct rtnl_tc *, void *, + struct nl_dump_params *); + /** + * Used to fill the contents of TCA_OPTIONS + */ + int (*to_msg_fill)(struct rtnl_tc *, void *, struct nl_msg *); + + /** + * Uesd to to fill tc related messages, unlike with to_msg_fill, + * the contents is not encapsulated with a TCA_OPTIONS nested + * attribute. + */ + int (*to_msg_fill_raw)(struct rtnl_tc *, void *, struct nl_msg *); + + /** + * TCA_OPTIONS message parser + */ + int (*to_msg_parser)(struct rtnl_tc *, void *); + + /** + * Called before a tc object is destroyed + */ + void (*to_free_data)(struct rtnl_tc *, void *); + + /** + * Called whenever a classifier object needs to be cloned + */ + int (*to_clone)(void *, void *); + + /** + * Internal, don't touch + */ + struct nl_list_head to_list; +}; + +struct rtnl_tc_type_ops +{ + enum rtnl_tc_type tt_type; + + char *tt_dump_prefix; + + /** + * Dump callbacks + */ + void (*tt_dump[NL_DUMP_MAX+1])(struct rtnl_tc *, + struct nl_dump_params *); +}; + +extern int rtnl_tc_msg_parse(struct nlmsghdr *, + struct rtnl_tc *); +extern int rtnl_tc_msg_build(struct rtnl_tc *, int, + int, struct nl_msg **); + +extern void rtnl_tc_free_data(struct nl_object *); +extern int rtnl_tc_clone(struct nl_object *, + struct nl_object *); +extern void rtnl_tc_dump_line(struct nl_object *, + struct nl_dump_params *); +extern void rtnl_tc_dump_details(struct nl_object *, + struct nl_dump_params *); +extern void rtnl_tc_dump_stats(struct nl_object *, + struct nl_dump_params *); +extern int rtnl_tc_compare(struct nl_object *, + struct nl_object *, + uint32_t, int); + +extern void * rtnl_tc_data(struct rtnl_tc *); +extern void * rtnl_tc_data_check(struct rtnl_tc *, + struct rtnl_tc_ops *); + +extern struct rtnl_tc_ops * rtnl_tc_lookup_ops(enum rtnl_tc_type, + const char *); +extern struct rtnl_tc_ops * rtnl_tc_get_ops(struct rtnl_tc *); +extern int rtnl_tc_register(struct rtnl_tc_ops *); +extern void rtnl_tc_unregister(struct rtnl_tc_ops *); + +extern void rtnl_tc_type_register(struct rtnl_tc_type_ops *); +extern void rtnl_tc_type_unregister(struct rtnl_tc_type_ops *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/route/tc.h b/libnetwork/libnl3/include/netlink/route/tc.h new file mode 100644 index 0000000..50ca6de --- /dev/null +++ b/libnetwork/libnl3/include/netlink/route/tc.h @@ -0,0 +1,105 @@ +/* + * netlink/route/tc.h Traffic Control + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +#ifndef NETLINK_TC_H_ +#define NETLINK_TC_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Compute tc handle based on major and minor parts + * @ingroup tc + */ +#define TC_HANDLE(maj, min) (TC_H_MAJ((maj) << 16) | TC_H_MIN(min)) + +/** + * Traffic control object + * @ingroup tc + */ +struct rtnl_tc; + +/** + * Macro to cast qdisc/class/classifier to tc object + * @ingroup tc + * + * @code + * rtnl_tc_set_mpu(TC_CAST(qdisc), 40); + * @endcode + */ +#define TC_CAST(ptr) ((struct rtnl_tc *) (ptr)) + +/** + * Traffic control statistical identifier + * @ingroup tc + * + * @code + * uint64_t n = rtnl_tc_get_stat(TC_CAST(class), RTNL_TC_PACKETS); + * @endcode + */ +enum rtnl_tc_stat { + RTNL_TC_PACKETS, /**< Number of packets seen */ + RTNL_TC_BYTES, /**< Total bytes seen */ + RTNL_TC_RATE_BPS, /**< Current bits/s (rate estimator) */ + RTNL_TC_RATE_PPS, /**< Current packet/s (rate estimator) */ + RTNL_TC_QLEN, /**< Current queue length */ + RTNL_TC_BACKLOG, /**< Current backlog length */ + RTNL_TC_DROPS, /**< Total number of packets dropped */ + RTNL_TC_REQUEUES, /**< Total number of requeues */ + RTNL_TC_OVERLIMITS, /**< Total number of overlimits */ + __RTNL_TC_STATS_MAX, +}; + +#define RTNL_TC_STATS_MAX (__RTNL_TC_STATS_MAX - 1) + +extern void rtnl_tc_set_ifindex(struct rtnl_tc *, int); +extern int rtnl_tc_get_ifindex(struct rtnl_tc *); +extern void rtnl_tc_set_link(struct rtnl_tc *, struct rtnl_link *); +extern struct rtnl_link *rtnl_tc_get_link(struct rtnl_tc *); +extern void rtnl_tc_set_mtu(struct rtnl_tc *, uint32_t); +extern uint32_t rtnl_tc_get_mtu(struct rtnl_tc *); +extern void rtnl_tc_set_mpu(struct rtnl_tc *, uint32_t); +extern uint32_t rtnl_tc_get_mpu(struct rtnl_tc *); +extern void rtnl_tc_set_overhead(struct rtnl_tc *, uint32_t); +extern uint32_t rtnl_tc_get_overhead(struct rtnl_tc *); +extern void rtnl_tc_set_linktype(struct rtnl_tc *, uint32_t); +extern uint32_t rtnl_tc_get_linktype(struct rtnl_tc *); +extern void rtnl_tc_set_handle(struct rtnl_tc *, uint32_t); +extern uint32_t rtnl_tc_get_handle(struct rtnl_tc *); +extern void rtnl_tc_set_parent(struct rtnl_tc *, uint32_t); +extern uint32_t rtnl_tc_get_parent(struct rtnl_tc *); +extern int rtnl_tc_set_kind(struct rtnl_tc *, const char *); +extern char * rtnl_tc_get_kind(struct rtnl_tc *); +extern uint64_t rtnl_tc_get_stat(struct rtnl_tc *, enum rtnl_tc_stat); + +extern int rtnl_tc_calc_txtime(int, int); +extern int rtnl_tc_calc_bufsize(int, int); +extern int rtnl_tc_calc_cell_log(int); + +extern int rtnl_tc_read_classid_file(void); +extern char * rtnl_tc_handle2str(uint32_t, char *, size_t); +extern int rtnl_tc_str2handle(const char *, uint32_t *); +extern int rtnl_classid_generate(const char *, uint32_t *, + uint32_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/socket.h b/libnetwork/libnl3/include/netlink/socket.h new file mode 100644 index 0000000..d0f5a6a --- /dev/null +++ b/libnetwork/libnl3/include/netlink/socket.h @@ -0,0 +1,69 @@ +/* + * netlink/socket.h Netlink Socket + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_SOCKET_H_ +#define NETLINK_SOCKET_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct nl_sock * nl_socket_alloc(void); +extern struct nl_sock * nl_socket_alloc_cb(struct nl_cb *); +extern void nl_socket_free(struct nl_sock *); + +extern uint32_t nl_socket_get_local_port(const struct nl_sock *); +extern void nl_socket_set_local_port(struct nl_sock *, uint32_t); + +extern int nl_socket_add_memberships(struct nl_sock *, int, ...); +extern int nl_socket_add_membership(struct nl_sock *, int); +extern int nl_socket_drop_memberships(struct nl_sock *, int, ...); +extern int nl_socket_drop_membership(struct nl_sock *, + int); +extern void nl_join_groups(struct nl_sock *, int); + + +extern uint32_t nl_socket_get_peer_port(const struct nl_sock *); +extern void nl_socket_set_peer_port(struct nl_sock *, + uint32_t); +extern uint32_t nl_socket_get_peer_groups(const struct nl_sock *sk); +extern void nl_socket_set_peer_groups(struct nl_sock *sk, uint32_t groups); +extern struct nl_cb * nl_socket_get_cb(const struct nl_sock *); +extern void nl_socket_set_cb(struct nl_sock *, + struct nl_cb *); +extern int nl_socket_modify_cb(struct nl_sock *, enum nl_cb_type, + enum nl_cb_kind, + nl_recvmsg_msg_cb_t, void *); +extern int nl_socket_modify_err_cb(struct nl_sock *, enum nl_cb_kind, + nl_recvmsg_err_cb_t, void *); + +extern int nl_socket_set_buffer_size(struct nl_sock *, int, int); +extern int nl_socket_set_passcred(struct nl_sock *, int); +extern int nl_socket_recv_pktinfo(struct nl_sock *, int); + +extern void nl_socket_disable_seq_check(struct nl_sock *); +extern unsigned int nl_socket_use_seq(struct nl_sock *); +extern void nl_socket_disable_auto_ack(struct nl_sock *); +extern void nl_socket_enable_auto_ack(struct nl_sock *); + +extern int nl_socket_get_fd(const struct nl_sock *); +extern int nl_socket_set_nonblocking(const struct nl_sock *); +extern void nl_socket_enable_msg_peek(struct nl_sock *); +extern void nl_socket_disable_msg_peek(struct nl_sock *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/types.h b/libnetwork/libnl3/include/netlink/types.h new file mode 100644 index 0000000..f6dade3 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/types.h @@ -0,0 +1,110 @@ +/* + * netlink/netlink-types.h Netlink Types + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef __NETLINK_TYPES_H_ +#define __NETLINK_TYPES_H_ + +#include + +/** + * Dumping types (dp_type) + * @ingroup utils + */ +enum nl_dump_type { + NL_DUMP_LINE, /**< Dump object briefly on one line */ + NL_DUMP_DETAILS, /**< Dump all attributes but no statistics */ + NL_DUMP_STATS, /**< Dump all attributes including statistics */ + __NL_DUMP_MAX, +}; +#define NL_DUMP_MAX (__NL_DUMP_MAX - 1) + +/** + * Dumping parameters + * @ingroup utils + */ +struct nl_dump_params +{ + /** + * Specifies the type of dump that is requested. + */ + enum nl_dump_type dp_type; + + /** + * Specifies the number of whitespaces to be put in front + * of every new line (indentation). + */ + int dp_prefix; + + /** + * Causes the cache index to be printed for each element. + */ + int dp_print_index; + + /** + * Causes each element to be prefixed with the message type. + */ + int dp_dump_msgtype; + + /** + * A callback invoked for output + * + * Passed arguments are: + * - dumping parameters + * - string to append to the output + */ + void (*dp_cb)(struct nl_dump_params *, char *); + + /** + * A callback invoked for every new line, can be used to + * customize the indentation. + * + * Passed arguments are: + * - dumping parameters + * - line number starting from 0 + */ + void (*dp_nl_cb)(struct nl_dump_params *, int); + + /** + * User data pointer, can be used to pass data to callbacks. + */ + void *dp_data; + + /** + * File descriptor the dumping output should go to + */ + FILE * dp_fd; + + /** + * Alternatively the output may be redirected into a buffer + */ + char * dp_buf; + + /** + * Length of the buffer dp_buf + */ + size_t dp_buflen; + + /** + * PRIVATE + * Set if a dump was performed prior to the actual dump handler. + */ + int dp_pre_dump; + + /** + * PRIVATE + * Owned by the current caller + */ + int dp_ivar; + + unsigned int dp_line; +}; + +#endif diff --git a/libnetwork/libnl3/include/netlink/utils.h b/libnetwork/libnl3/include/netlink/utils.h new file mode 100644 index 0000000..a1ef82e --- /dev/null +++ b/libnetwork/libnl3/include/netlink/utils.h @@ -0,0 +1,85 @@ +/* + * netlink/utils.h Utility Functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_UTILS_H_ +#define NETLINK_UTILS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Probability Constants + * @{ + */ + +/** + * Lower probability limit + * @ingroup utils + */ +#define NL_PROB_MIN 0x0 + +/** + * Upper probability limit + * @ingroup utils + */ +#define NL_PROB_MAX 0xffffffff + +/** @} */ + +enum { + NL_BYTE_RATE, + NL_BIT_RATE, +}; + +/* unit pretty-printing */ +extern double nl_cancel_down_bytes(unsigned long long, char **); +extern double nl_cancel_down_bits(unsigned long long, char **); +extern int nl_rate2str(unsigned long long, int, char *, size_t); +extern double nl_cancel_down_us(uint32_t, char **); + +/* generic unit translations */ +extern long nl_size2int(const char *); +extern char * nl_size2str(const size_t, char *, const size_t); +extern long nl_prob2int(const char *); + +/* time translations */ +extern int nl_get_user_hz(void); +extern uint32_t nl_us2ticks(uint32_t); +extern uint32_t nl_ticks2us(uint32_t); +extern int nl_str2msec(const char *, uint64_t *); +extern char * nl_msec2str(uint64_t, char *, size_t); + +/* link layer protocol translations */ +extern char * nl_llproto2str(int, char *, size_t); +extern int nl_str2llproto(const char *); + +/* ethernet protocol translations */ +extern char * nl_ether_proto2str(int, char *, size_t); +extern int nl_str2ether_proto(const char *); + +/* IP protocol translations */ +extern char * nl_ip_proto2str(int, char *, size_t); +extern int nl_str2ip_proto(const char *); + +/* Dumping helpers */ +extern void nl_new_line(struct nl_dump_params *); +extern void nl_dump(struct nl_dump_params *, const char *, ...); +extern void nl_dump_line(struct nl_dump_params *, const char *, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libnetwork/libnl3/include/netlink/version.h b/libnetwork/libnl3/include/netlink/version.h new file mode 100644 index 0000000..85d1831 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/version.h @@ -0,0 +1,28 @@ +/* + * netlink/version.h Compile Time Versioning Information + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2011 Thomas Graf + */ + +#ifndef NETLINK_VERSION_H_ +#define NETLINK_VERSION_H_ + +#define LIBNL_STRING "libnl 3.2.3" +#define LIBNL_VERSION "3.2.3" + +#define LIBNL_VER_MAJ 3 +#define LIBNL_VER_MIN 2 +#define LIBNL_VER_MIC 3 +#define LIBNL_VER(maj,min) ((maj) << 8 | (min)) +#define LIBNL_VER_NUM LIBNL_VER(LIBNL_VER_MAJ, LIBNL_VER_MIN) + +#define LIBNL_CURRENT 203 +#define LIBNL_REVISION 0 +#define LIBNL_AGE 3 + +#endif diff --git a/libnetwork/libnl3/include/netlink/version.h.in b/libnetwork/libnl3/include/netlink/version.h.in new file mode 100644 index 0000000..ac56799 --- /dev/null +++ b/libnetwork/libnl3/include/netlink/version.h.in @@ -0,0 +1,28 @@ +/* + * netlink/version.h Compile Time Versioning Information + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2011 Thomas Graf + */ + +#ifndef NETLINK_VERSION_H_ +#define NETLINK_VERSION_H_ + +#define LIBNL_STRING "@PACKAGE_STRING@" +#define LIBNL_VERSION "@PACKAGE_VERSION@" + +#define LIBNL_VER_MAJ @MAJ_VERSION@ +#define LIBNL_VER_MIN @MIN_VERSION@ +#define LIBNL_VER_MIC @MIC_VERSION@ +#define LIBNL_VER(maj,min) ((maj) << 8 | (min)) +#define LIBNL_VER_NUM LIBNL_VER(LIBNL_VER_MAJ, LIBNL_VER_MIN) + +#define LIBNL_CURRENT @LT_CURRENT@ +#define LIBNL_REVISION @LT_REVISION@ +#define LIBNL_AGE @LT_AGE@ + +#endif diff --git a/libnetwork/libnl3/lib/addr.c b/libnetwork/libnl3/lib/addr.c new file mode 100644 index 0000000..c8c4ca4 --- /dev/null +++ b/libnetwork/libnl3/lib/addr.c @@ -0,0 +1,918 @@ +/* + * lib/addr.c Abstract Address + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2010 Thomas Graf + */ + +/** + * @ingroup core + * @defgroup addr Abstract Address + * + * @par 1) Transform character string to abstract address + * @code + * struct nl_addr *a = nl_addr_parse("::1", AF_UNSPEC); + * printf("Address family: %s\n", nl_af2str(nl_addr_get_family(a))); + * nl_addr_put(a); + * a = nl_addr_parse("11:22:33:44:55:66", AF_UNSPEC); + * printf("Address family: %s\n", nl_af2str(nl_addr_get_family(a))); + * nl_addr_put(a); + * @endcode + * @{ + */ + +#include +#include +#include +#include +#include + +/* All this DECnet stuff is stolen from iproute2, thanks to whoever wrote + * this, probably Alexey. */ +static inline uint16_t dn_ntohs(uint16_t addr) +{ + union { + uint8_t byte[2]; + uint16_t word; + } u = { + .word = addr, + }; + + return ((uint16_t) u.byte[0]) | (((uint16_t) u.byte[1]) << 8); +} + +static inline int do_digit(char *str, uint16_t *addr, uint16_t scale, + size_t *pos, size_t len, int *started) +{ + uint16_t tmp = *addr / scale; + + if (*pos == len) + return 1; + + if (((tmp) > 0) || *started || (scale == 1)) { + *str = tmp + '0'; + *started = 1; + (*pos)++; + *addr -= (tmp * scale); + } + + return 0; +} + +static const char *dnet_ntop(char *addrbuf, size_t addrlen, char *str, + size_t len) +{ + uint16_t addr = dn_ntohs(*(uint16_t *)addrbuf); + uint16_t area = addr >> 10; + size_t pos = 0; + int started = 0; + + if (addrlen != 2) + return NULL; + + addr &= 0x03ff; + + if (len == 0) + return str; + + if (do_digit(str + pos, &area, 10, &pos, len, &started)) + return str; + + if (do_digit(str + pos, &area, 1, &pos, len, &started)) + return str; + + if (pos == len) + return str; + + *(str + pos) = '.'; + pos++; + started = 0; + + if (do_digit(str + pos, &addr, 1000, &pos, len, &started)) + return str; + + if (do_digit(str + pos, &addr, 100, &pos, len, &started)) + return str; + + if (do_digit(str + pos, &addr, 10, &pos, len, &started)) + return str; + + if (do_digit(str + pos, &addr, 1, &pos, len, &started)) + return str; + + if (pos == len) + return str; + + *(str + pos) = 0; + + return str; +} + +static int dnet_num(const char *src, uint16_t * dst) +{ + int rv = 0; + int tmp; + *dst = 0; + + while ((tmp = *src++) != 0) { + tmp -= '0'; + if ((tmp < 0) || (tmp > 9)) + return rv; + + rv++; + (*dst) *= 10; + (*dst) += tmp; + } + + return rv; +} + +static inline int dnet_pton(const char *src, char *addrbuf) +{ + uint16_t area = 0; + uint16_t node = 0; + int pos; + + pos = dnet_num(src, &area); + if ((pos == 0) || (area > 63) || + ((*(src + pos) != '.') && (*(src + pos) != ','))) + return -NLE_INVAL; + + pos = dnet_num(src + pos + 1, &node); + if ((pos == 0) || (node > 1023)) + return -NLE_INVAL; + + *(uint16_t *)addrbuf = dn_ntohs((area << 10) | node); + + return 1; +} + +static void addr_destroy(struct nl_addr *addr) +{ + if (!addr) + return; + + if (addr->a_refcnt != 1) + BUG(); + + free(addr); +} + +/** + * @name Creating Abstract Addresses + * @{ + */ + +/** + * Allocate new abstract address object. + * @arg maxsize Maximum size of the binary address. + * @return Newly allocated address object or NULL + */ +struct nl_addr *nl_addr_alloc(size_t maxsize) +{ + struct nl_addr *addr; + + addr = calloc(1, sizeof(*addr) + maxsize); + if (!addr) + return NULL; + + addr->a_refcnt = 1; + addr->a_maxsize = maxsize; + + return addr; +} + +/** + * Allocate new abstract address object based on a binary address. + * @arg family Address family. + * @arg buf Buffer containing the binary address. + * @arg size Length of binary address buffer. + * @return Newly allocated address handle or NULL + */ +struct nl_addr *nl_addr_build(int family, void *buf, size_t size) +{ + struct nl_addr *addr; + + addr = nl_addr_alloc(size); + if (!addr) + return NULL; + + addr->a_family = family; + addr->a_len = size; + addr->a_prefixlen = size*8; + + if (size) + memcpy(addr->a_addr, buf, size); + + return addr; +} + +/** + * Allocate abstract address based on netlink attribute. + * @arg nla Netlink attribute of unspecific type. + * @arg family Address family. + * + * Considers the netlink attribute payload a address of the specified + * family and allocates a new abstract address based on it. + * + * @return Newly allocated address handle or NULL. + */ +struct nl_addr *nl_addr_alloc_attr(struct nlattr *nla, int family) +{ + return nl_addr_build(family, nla_data(nla), nla_len(nla)); +} + +/** + * Allocate abstract address object based on a character string + * @arg addrstr Address represented as character string. + * @arg hint Address family hint or AF_UNSPEC. + * @arg result Pointer to store resulting address. + * + * Regognizes the following address formats: + *@code + * Format Len Family + * ---------------------------------------------------------------- + * IPv6 address format 16 AF_INET6 + * ddd.ddd.ddd.ddd 4 AF_INET + * HH:HH:HH:HH:HH:HH 6 AF_LLC + * AA{.|,}NNNN 2 AF_DECnet + * HH:HH:HH:... variable AF_UNSPEC + * @endcode + * + * Special values: + * - none: All bits and length set to 0. + * - {default|all|any}: All bits set to 0, length based on hint or + * AF_INET if no hint is given. + * + * The prefix length may be appened at the end prefixed with a + * slash, e.g. 10.0.0.0/8. + * + * @return 0 on success or a negative error code. + */ +int nl_addr_parse(const char *addrstr, int hint, struct nl_addr **result) +{ + int err, copy = 0, len = 0, family = AF_UNSPEC; + char *str, *prefix, buf[32]; + struct nl_addr *addr = NULL; /* gcc ain't that smart */ + + str = strdup(addrstr); + if (!str) { + err = -NLE_NOMEM; + goto errout; + } + + prefix = strchr(str, '/'); + if (prefix) + *prefix = '\0'; + + if (!strcasecmp(str, "none")) { + family = hint; + goto prefix; + } + + if (!strcasecmp(str, "default") || + !strcasecmp(str, "all") || + !strcasecmp(str, "any")) { + + switch (hint) { + case AF_INET: + case AF_UNSPEC: + /* Kind of a hack, we assume that if there is + * no hint given the user wants to have a IPv4 + * address given back. */ + family = AF_INET; + len = 4; + goto prefix; + + case AF_INET6: + family = AF_INET6; + len = 16; + goto prefix; + + case AF_LLC: + family = AF_LLC; + len = 6; + goto prefix; + + default: + err = -NLE_AF_NOSUPPORT; + goto errout; + } + } + + copy = 1; + + if (hint == AF_INET || hint == AF_UNSPEC) { + if (inet_pton(AF_INET, str, buf) > 0) { + family = AF_INET; + len = 4; + goto prefix; + } + if (hint == AF_INET) { + err = -NLE_NOADDR; + goto errout; + } + } + + if (hint == AF_INET6 || hint == AF_UNSPEC) { + if (inet_pton(AF_INET6, str, buf) > 0) { + family = AF_INET6; + len = 16; + goto prefix; + } + if (hint == AF_INET6) { + err = -NLE_NOADDR; + goto errout; + } + } + + if ((hint == AF_LLC || hint == AF_UNSPEC) && strchr(str, ':')) { + unsigned int a, b, c, d, e, f; + + if (sscanf(str, "%02x:%02x:%02x:%02x:%02x:%02x", + &a, &b, &c, &d, &e, &f) == 6) { + family = AF_LLC; + len = 6; + buf[0] = (unsigned char) a; + buf[1] = (unsigned char) b; + buf[2] = (unsigned char) c; + buf[3] = (unsigned char) d; + buf[4] = (unsigned char) e; + buf[5] = (unsigned char) f; + goto prefix; + } + + if (hint == AF_LLC) { + err = -NLE_NOADDR; + goto errout; + } + } + + if ((hint == AF_DECnet || hint == AF_UNSPEC) && + (strchr(str, '.') || strchr(str, ','))) { + if (dnet_pton(str, buf) > 0) { + family = AF_DECnet; + len = 2; + goto prefix; + } + if (hint == AF_DECnet) { + err = -NLE_NOADDR; + goto errout; + } + } + + if (hint == AF_UNSPEC && strchr(str, ':')) { + int i = 0; + char *s = str, *p; + for (;;) { + long l = strtol(s, &p, 16); + + if (s == p || l > 0xff || i >= sizeof(buf)) { + err = -NLE_INVAL; + goto errout; + } + + buf[i++] = (unsigned char) l; + if (*p == '\0') + break; + s = ++p; + } + + len = i; + family = AF_UNSPEC; + goto prefix; + } + + err = -NLE_NOADDR; + goto errout; + +prefix: + addr = nl_addr_alloc(len); + if (!addr) { + err = -NLE_NOMEM; + goto errout; + } + + nl_addr_set_family(addr, family); + + if (copy) + nl_addr_set_binary_addr(addr, buf, len); + + if (prefix) { + char *p; + long pl = strtol(++prefix, &p, 0); + if (p == prefix) { + addr_destroy(addr); + err = -NLE_INVAL; + goto errout; + } + nl_addr_set_prefixlen(addr, pl); + } else + nl_addr_set_prefixlen(addr, len * 8); + + *result = addr; + err = 0; +errout: + free(str); + + return err; +} + +/** + * Clone existing abstract address object. + * @arg addr Abstract address object. + * @return Newly allocated abstract address object being a duplicate of the + * specified address object or NULL if a failure occured. + */ +struct nl_addr *nl_addr_clone(struct nl_addr *addr) +{ + struct nl_addr *new; + + new = nl_addr_build(addr->a_family, addr->a_addr, addr->a_len); + if (new) + new->a_prefixlen = addr->a_prefixlen; + + return new; +} + +/** @} */ + +/** + * @name Managing Usage References + * @{ + */ + +struct nl_addr *nl_addr_get(struct nl_addr *addr) +{ + addr->a_refcnt++; + + return addr; +} + +void nl_addr_put(struct nl_addr *addr) +{ + if (!addr) + return; + + if (addr->a_refcnt == 1) + addr_destroy(addr); + else + addr->a_refcnt--; +} + +/** + * Check whether an abstract address object is shared. + * @arg addr Abstract address object. + * @return Non-zero if the abstract address object is shared, otherwise 0. + */ +int nl_addr_shared(struct nl_addr *addr) +{ + return addr->a_refcnt > 1; +} + +/** @} */ + +/** + * @name Miscellaneous + * @{ + */ + +/** + * Compares two abstract address objects. + * @arg a A abstract address object. + * @arg b Another abstract address object. + * + * @return Integer less than, equal to or greather than zero if \c is found, + * respectively to be less than, to, or be greater than \c b. + */ +int nl_addr_cmp(struct nl_addr *a, struct nl_addr *b) +{ + int d = a->a_family - b->a_family; + + if (d == 0) { + d = a->a_len - b->a_len; + + if (a->a_len && d == 0) + return memcmp(a->a_addr, b->a_addr, a->a_len); + } + + return d; +} + +/** + * Compares the prefix of two abstract address objects. + * @arg a A abstract address object. + * @arg b Another abstract address object. + * + * @return Integer less than, equal to or greather than zero if \c is found, + * respectively to be less than, to, or be greater than \c b. + */ +int nl_addr_cmp_prefix(struct nl_addr *a, struct nl_addr *b) +{ + int d = a->a_family - b->a_family; + + if (d == 0) { + int len = min(a->a_prefixlen, b->a_prefixlen); + int bytes = len / 8; + + d = memcmp(a->a_addr, b->a_addr, bytes); + if (d == 0) { + int mask = (1UL << (len % 8)) - 1UL; + + d = (a->a_addr[bytes] & mask) - + (b->a_addr[bytes] & mask); + } + } + + return d; +} + +/** + * Returns true if the address consists of all zeros + * @arg addr Address to look at. + */ +int nl_addr_iszero(struct nl_addr *addr) +{ + int i; + + for (i = 0; i < addr->a_len; i++) + if (addr->a_addr[i]) + return 0; + + return 1; +} + +/** + * Check if an address matches a certain family. + * @arg addr Address represented as character string. + * @arg family Desired address family. + * + * @return 1 if the address is of the desired address family, + * otherwise 0 is returned. + */ +int nl_addr_valid(char *addr, int family) +{ + int ret; + char buf[32]; + + switch (family) { + case AF_INET: + case AF_INET6: + ret = inet_pton(family, addr, buf); + if (ret <= 0) + return 0; + break; + + case AF_DECnet: + ret = dnet_pton(addr, buf); + if (ret <= 0) + return 0; + break; + + case AF_LLC: + if (sscanf(addr, "%*02x:%*02x:%*02x:%*02x:%*02x:%*02x") != 6) + return 0; + break; + } + + return 1; +} + +/** + * Guess address family of an abstract address object based on address size. + * @arg addr Abstract address object. + * @return Address family or AF_UNSPEC if guessing wasn't successful. + */ +int nl_addr_guess_family(struct nl_addr *addr) +{ + switch (addr->a_len) { + case 4: + return AF_INET; + case 6: + return AF_LLC; + case 16: + return AF_INET6; + default: + return AF_UNSPEC; + } +} + +/** + * Fill out sockaddr structure with values from abstract address object. + * @arg addr Abstract address object. + * @arg sa Destination sockaddr structure buffer. + * @arg salen Length of sockaddr structure buffer. + * + * Fills out the specified sockaddr structure with the data found in the + * specified abstract address. The salen argument needs to be set to the + * size of sa but will be modified to the actual size used during before + * the function exits. + * + * @return 0 on success or a negative error code + */ +int nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa, + socklen_t *salen) +{ + switch (addr->a_family) { + case AF_INET: { + struct sockaddr_in *sai = (struct sockaddr_in *) sa; + + if (*salen < sizeof(*sai)) + return -NLE_INVAL; + + sai->sin_family = addr->a_family; + memcpy(&sai->sin_addr, addr->a_addr, 4); + *salen = sizeof(*sai); + } + break; + + case AF_INET6: { + struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa; + + if (*salen < sizeof(*sa6)) + return -NLE_INVAL; + + sa6->sin6_family = addr->a_family; + memcpy(&sa6->sin6_addr, addr->a_addr, 16); + *salen = sizeof(*sa6); + } + break; + + default: + return -NLE_INVAL; + } + + return 0; +} + + +/** @} */ + +/** + * @name Getting Information About Addresses + * @{ + */ + +/** + * Call getaddrinfo() for an abstract address object. + * @arg addr Abstract address object. + * @arg result Pointer to store resulting address list. + * + * Calls getaddrinfo() for the specified abstract address in AI_NUMERICHOST + * mode. + * + * @note The caller is responsible for freeing the linked list using the + * interface provided by getaddrinfo(3). + * + * @return 0 on success or a negative error code. + */ +int nl_addr_info(struct nl_addr *addr, struct addrinfo **result) +{ + int err; + char buf[INET6_ADDRSTRLEN+5]; + struct addrinfo hint = { + .ai_flags = AI_NUMERICHOST, + .ai_family = addr->a_family, + }; + + nl_addr2str(addr, buf, sizeof(buf)); + + err = getaddrinfo(buf, NULL, &hint, result); + if (err != 0) { + switch (err) { + case EAI_ADDRFAMILY: return -NLE_AF_NOSUPPORT; + case EAI_AGAIN: return -NLE_AGAIN; + case EAI_BADFLAGS: return -NLE_INVAL; + case EAI_FAIL: return -NLE_NOADDR; + case EAI_FAMILY: return -NLE_AF_NOSUPPORT; + case EAI_MEMORY: return -NLE_NOMEM; + case EAI_NODATA: return -NLE_NOADDR; + case EAI_NONAME: return -NLE_OBJ_NOTFOUND; + case EAI_SERVICE: return -NLE_OPNOTSUPP; + case EAI_SOCKTYPE: return -NLE_BAD_SOCK; + default: return -NLE_FAILURE; + } + } + + return 0; +} + +/** + * Resolve abstract address object to a name using getnameinfo(). + * @arg addr Abstract address object. + * @arg host Destination buffer for host name. + * @arg hostlen Length of destination buffer. + * + * Resolves the abstract address to a name and writes the looked up result + * into the host buffer. getnameinfo() is used to perform the lookup and + * is put into NI_NAMEREQD mode so the function will fail if the lookup + * couldn't be performed. + * + * @return 0 on success or a negative error code. + */ +int nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen) +{ + int err; + struct sockaddr_in6 buf; + socklen_t salen = sizeof(buf); + + err = nl_addr_fill_sockaddr(addr, (struct sockaddr *) &buf, &salen); + if (err < 0) + return err; + + err = getnameinfo((struct sockaddr *) &buf, salen, host, hostlen, + NULL, 0, NI_NAMEREQD); + if (err < 0) + return nl_syserr2nlerr(err); + + return 0; +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void nl_addr_set_family(struct nl_addr *addr, int family) +{ + addr->a_family = family; +} + +int nl_addr_get_family(struct nl_addr *addr) +{ + return addr->a_family; +} + +/** + * Set binary address of abstract address object. + * @arg addr Abstract address object. + * @arg buf Buffer containing binary address. + * @arg len Length of buffer containing binary address. + */ +int nl_addr_set_binary_addr(struct nl_addr *addr, void *buf, size_t len) +{ + if (len > addr->a_maxsize) + return -NLE_RANGE; + + addr->a_len = len; + memcpy(addr->a_addr, buf, len); + + return 0; +} + +/** + * Get binary address of abstract address object. + * @arg addr Abstract address object. + */ +void *nl_addr_get_binary_addr(struct nl_addr *addr) +{ + return addr->a_addr; +} + +/** + * Get length of binary address of abstract address object. + * @arg addr Abstract address object. + */ +unsigned int nl_addr_get_len(struct nl_addr *addr) +{ + return addr->a_len; +} + +void nl_addr_set_prefixlen(struct nl_addr *addr, int prefixlen) +{ + addr->a_prefixlen = prefixlen; +} + +/** + * Get prefix length of abstract address object. + * @arg addr Abstract address object. + */ +unsigned int nl_addr_get_prefixlen(struct nl_addr *addr) +{ + return addr->a_prefixlen; +} + +/** @} */ + +/** + * @name Translations to Strings + * @{ + */ + +/** + * Convert abstract address object to character string. + * @arg addr Abstract address object. + * @arg buf Destination buffer. + * @arg size Size of destination buffer. + * + * Converts an abstract address to a character string and stores + * the result in the specified destination buffer. + * + * @return Address represented in ASCII stored in destination buffer. + */ +char *nl_addr2str(struct nl_addr *addr, char *buf, size_t size) +{ + int i; + char tmp[16]; + + if (!addr || !addr->a_len) { + snprintf(buf, size, "none"); + if (addr) + goto prefix; + else + return buf; + } + + switch (addr->a_family) { + case AF_INET: + inet_ntop(AF_INET, addr->a_addr, buf, size); + break; + + case AF_INET6: + inet_ntop(AF_INET6, addr->a_addr, buf, size); + break; + + case AF_DECnet: + dnet_ntop(addr->a_addr, addr->a_len, buf, size); + break; + + case AF_LLC: + default: + snprintf(buf, size, "%02x", + (unsigned char) addr->a_addr[0]); + for (i = 1; i < addr->a_len; i++) { + snprintf(tmp, sizeof(tmp), ":%02x", + (unsigned char) addr->a_addr[i]); + strncat(buf, tmp, size - strlen(buf) - 1); + } + break; + } + +prefix: + if (addr->a_prefixlen != (8 * addr->a_len)) { + snprintf(tmp, sizeof(tmp), "/%u", addr->a_prefixlen); + strncat(buf, tmp, size - strlen(buf) - 1); + } + + return buf; +} + +/** @} */ + +/** + * @name Address Family Transformations + * @{ + */ + +static const struct trans_tbl afs[] = { + __ADD(AF_UNSPEC,unspec) + __ADD(AF_UNIX,unix) + __ADD(AF_LOCAL,local) + __ADD(AF_INET,inet) + __ADD(AF_AX25,ax25) + __ADD(AF_IPX,ipx) + __ADD(AF_APPLETALK,appletalk) + __ADD(AF_NETROM,netrom) + __ADD(AF_BRIDGE,bridge) + __ADD(AF_ATMPVC,atmpvc) + __ADD(AF_X25,x25) + __ADD(AF_INET6,inet6) + __ADD(AF_ROSE,rose) + __ADD(AF_DECnet,decnet) + __ADD(AF_NETBEUI,netbeui) + __ADD(AF_SECURITY,security) + __ADD(AF_KEY,key) + __ADD(AF_NETLINK,netlink) + __ADD(AF_ROUTE,route) + __ADD(AF_PACKET,packet) + __ADD(AF_ASH,ash) + __ADD(AF_ECONET,econet) + __ADD(AF_ATMSVC,atmsvc) + __ADD(AF_SNA,sna) + __ADD(AF_IRDA,irda) + __ADD(AF_PPPOX,pppox) + __ADD(AF_WANPIPE,wanpipe) + __ADD(AF_LLC,llc) + __ADD(AF_BLUETOOTH,bluetooth) +}; + +char *nl_af2str(int family, char *buf, size_t size) +{ + return __type2str(family, buf, size, afs, ARRAY_SIZE(afs)); +} + +int nl_str2af(const char *name) +{ + int fam = __str2type(name, afs, ARRAY_SIZE(afs)); + return fam >= 0 ? fam : -EINVAL; +} + +/** @} */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/attr.c b/libnetwork/libnl3/lib/attr.c new file mode 100644 index 0000000..a045351 --- /dev/null +++ b/libnetwork/libnl3/lib/attr.c @@ -0,0 +1,1213 @@ +/* + * lib/attr.c Netlink Attributes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#include +#include +#include +#include +#include +#include +#include + +/** + * @ingroup msg + * @defgroup attr Attributes + * Netlink Attributes Construction/Parsing Interface + * + * \section attr_sec Netlink Attributes + * Netlink attributes allow for data chunks of arbitary length to be + * attached to a netlink message. Each attribute is encoded with a + * type and length field, both 16 bits, stored in the attribute header + * preceding the attribute data. The main advantage of using attributes + * over packing everything into the family header is that the interface + * stays extendable as new attributes can supersede old attributes while + * remaining backwards compatible. Also attributes can be defined optional + * thus avoiding the transmission of unnecessary empty data blocks. + * Special nested attributes allow for more complex data structures to + * be transmitted, e.g. trees, lists, etc. + * + * While not required, netlink attributes typically follow the family + * header of a netlink message and must be properly aligned to NLA_ALIGNTO: + * @code + * +----------------+- - -+---------------+- - -+------------+- - -+ + * | Netlink Header | Pad | Family Header | Pad | Attributes | Pad | + * +----------------+- - -+---------------+- - -+------------+- - -+ + * @endcode + * + * The actual attributes are chained together each separately aligned to + * NLA_ALIGNTO. The position of an attribute is defined based on the + * length field of the preceding attributes: + * @code + * +-------------+- - -+-------------+- - -+------ + * | Attribute 1 | Pad | Attribute 2 | Pad | ... + * +-------------+- - -+-------------+- - -+------ + * nla_next(attr1)------^ + * @endcode + * + * The attribute itself consists of the attribute header followed by + * the actual payload also aligned to NLA_ALIGNTO. The function nla_data() + * returns a pointer to the start of the payload while nla_len() returns + * the length of the payload in bytes. + * + * \b Note: Be aware, NLA_ALIGNTO equals to 4 bytes, therefore it is not + * safe to dereference any 64 bit data types directly. + * + * @code + * <----------- nla_total_size(payload) -----------> + * <-------- nla_attr_size(payload) ---------> + * +------------------+- - -+- - - - - - - - - +- - -+ + * | Attribute Header | Pad | Payload | Pad | + * +------------------+- - -+- - - - - - - - - +- - -+ + * nla_data(nla)-------------^ + * <- nla_len(nla) -> + * @endcode + * + * @subsection attr_datatypes Attribute Data Types + * A number of basic data types are supported to simplify access and + * validation of netlink attributes. This data type information is + * not encoded in the attribute, both the kernel and userspace part + * are required to share this information on their own. + * + * One of the major advantages of these basic types is the automatic + * validation of each attribute based on an attribute policy. The + * validation covers most of the checks required to safely use + * attributes and thus keeps the individual sanity check to a minimum. + * + * Never access attribute payload without ensuring basic validation + * first, attributes may: + * - not be present even though required + * - contain less actual payload than expected + * - fake a attribute length which exceeds the end of the message + * - contain unterminated character strings + * + * Policies are defined as array of the struct nla_policy. The array is + * indexed with the attribute type, therefore the array must be sized + * accordingly. + * @code + * static struct nla_policy my_policy[ATTR_MAX+1] = { + * [ATTR_FOO] = { .type = ..., .minlen = ..., .maxlen = ... }, + * }; + * + * err = nla_validate(attrs, attrlen, ATTR_MAX, &my_policy); + * @endcode + * + * Some basic validations are performed on every attribute, regardless of type. + * - If the attribute type exceeds the maximum attribute type specified or + * the attribute type is lesser-or-equal than zero, the attribute will + * be silently ignored. + * - If the payload length falls below the \a minlen value the attribute + * will be rejected. + * - If \a maxlen is non-zero and the payload length exceeds the \a maxlen + * value the attribute will be rejected. + * + * + * @par Unspecific Attribute (NLA_UNSPEC) + * This is the standard type if no type is specified. It is used for + * binary data of arbitary length. Typically this attribute carries + * a binary structure or a stream of bytes. + * @par + * @code + * // In this example, we will assume a binary structure requires to + * // be transmitted. The definition of the structure will typically + * // go into a header file available to both the kernel and userspace + * // side. + * // + * // Note: Be careful when putting 64 bit data types into a structure. + * // The attribute payload is only aligned to 4 bytes, dereferencing + * // the member may fail. + * struct my_struct { + * int a; + * int b; + * }; + * + * // The validation function will not enforce an exact length match to + * // allow structures to grow as required. Note: While it is allowed + * // to add members to the end of the structure, changing the order or + * // inserting members in the middle of the structure will break your + * // binary interface. + * static struct nla_policy my_policy[ATTR_MAX+1] = { + * [ATTR_MY_STRICT] = { .type = NLA_UNSPEC, + * .minlen = sizeof(struct my_struct) }, + * + * // The binary structure is appened to the message using nla_put() + * struct my_struct foo = { .a = 1, .b = 2 }; + * nla_put(msg, ATTR_MY_STRUCT, sizeof(foo), &foo); + * + * // On the receiving side, a pointer to the structure pointing inside + * // the message payload is returned by nla_get(). + * if (attrs[ATTR_MY_STRUCT]) + * struct my_struct *foo = nla_get(attrs[ATTR_MY_STRUCT]); + * @endcode + * + * @par Integers (NLA_U8, NLA_U16, NLA_U32, NLA_U64) + * Integers come in different sizes from 8 bit to 64 bit. However, since the + * payload length is aligned to 4 bytes, integers smaller than 32 bit are + * only useful to enforce the maximum range of values. + * @par + * \b Note: There is no difference made between signed and unsigned integers. + * The validation only enforces the minimal payload length required to store + * an integer of specified type. + * @par + * @code + * // Even though possible, it does not make sense to specify .minlen or + * // .maxlen for integer types. The data types implies the corresponding + * // minimal payload length. + * static struct nla_policy my_policy[ATTR_MAX+1] = { + * [ATTR_FOO] = { .type = NLA_U32 }, + * + * // Numeric values can be appended directly using the respective + * // nla_put_uxxx() function + * nla_put_u32(msg, ATTR_FOO, 123); + * + * // Same for the receiving side. + * if (attrs[ATTR_FOO]) + * uint32_t foo = nla_get_u32(attrs[ATTR_FOO]); + * @endcode + * + * @par Character string (NLA_STRING) + * This data type represents a NUL terminated character string of variable + * length. For binary data streams the type NLA_UNSPEC is recommended. + * @par + * @code + * // Enforce a NUL terminated character string of at most 4 characters + * // including the NUL termination. + * static struct nla_policy my_policy[ATTR_MAX+1] = { + * [ATTR_BAR] = { .type = NLA_STRING, maxlen = 4 }, + * + * // nla_put_string() creates a string attribute of the necessary length + * // and appends it to the message including the NUL termination. + * nla_put_string(msg, ATTR_BAR, "some text"); + * + * // It is safe to use the returned character string directly if the + * // attribute has been validated as the validation enforces the proper + * // termination of the string. + * if (attrs[ATTR_BAR]) + * char *text = nla_get_string(attrs[ATTR_BAR]); + * @endcode + * + * @par Flag (NLA_FLAG) + * This attribute type may be used to indicate the presence of a flag. The + * attribute is only valid if the payload length is zero. The presence of + * the attribute header indicates the presence of the flag. + * @par + * @code + * // This attribute type is special as .minlen and .maxlen have no effect. + * static struct nla_policy my_policy[ATTR_MAX+1] = { + * [ATTR_FLAG] = { .type = NLA_FLAG }, + * + * // nla_put_flag() appends a zero sized attribute to the message. + * nla_put_flag(msg, ATTR_FLAG); + * + * // There is no need for a receival function, the presence is the value. + * if (attrs[ATTR_FLAG]) + * // flag is present + * @endcode + * + * @par Micro Seconds (NLA_MSECS) + * + * @par Nested Attribute (NLA_NESTED) + * Attributes can be nested and put into a container to create groups, lists + * or to construct trees of attributes. Nested attributes are often used to + * pass attributes to a subsystem where the top layer has no knowledge of the + * configuration possibilities of each subsystem. + * @par + * \b Note: When validating the attributes using nlmsg_validate() or + * nlmsg_parse() it will only affect the top level attributes. Each + * level of nested attributes must be validated seperately using + * nla_parse_nested() or nla_validate(). + * @par + * @code + * // The minimal length policy may be used to enforce the presence of at + * // least one attribute. + * static struct nla_policy my_policy[ATTR_MAX+1] = { + * [ATTR_OPTS] = { .type = NLA_NESTED, minlen = NLA_HDRLEN }, + * + * // Nested attributes are constructed by enclosing the attributes + * // to be nested with calls to nla_nest_start() respetively nla_nest_end(). + * struct nlattr *opts = nla_nest_start(msg, ATTR_OPTS); + * nla_put_u32(msg, ATTR_FOO, 123); + * nla_put_string(msg, ATTR_BAR, "some text"); + * nla_nest_end(msg, opts); + * + * // Various methods exist to parse nested attributes, the easiest being + * // nla_parse_nested() which also allows validation in the same step. + * if (attrs[ATTR_OPTS]) { + * struct nlattr *nested[ATTR_MAX+1]; + * + * nla_parse_nested(nested, ATTR_MAX, attrs[ATTR_OPTS], &policy); + * + * if (nested[ATTR_FOO]) + * uint32_t foo = nla_get_u32(nested[ATTR_FOO]); + * } + * @endcode + * + * @subsection attr_exceptions Exception Based Attribute Construction + * Often a large number of attributes are added to a message in a single + * function. In order to simplify error handling, a second set of + * construction functions exist which jump to a error label when they + * fail instead of returning an error code. This second set consists + * of macros which are named after their error code based counterpart + * except that the name is written all uppercase. + * + * All of the macros jump to the target \c nla_put_failure if they fail. + * @code + * void my_func(struct nl_msg *msg) + * { + * NLA_PUT_U32(msg, ATTR_FOO, 10); + * NLA_PUT_STRING(msg, ATTR_BAR, "bar"); + * + * return 0; + * + * nla_put_failure: + * return -NLE_NOMEM; + * } + * @endcode + * + * @subsection attr_examples Examples + * @par Example 1.1 Constructing a netlink message with attributes. + * @code + * struct nl_msg *build_msg(int ifindex, struct nl_addr *lladdr, int mtu) + * { + * struct nl_msg *msg; + * struct nlattr *info, *vlan; + * struct ifinfomsg ifi = { + * .ifi_family = AF_INET, + * .ifi_index = ifindex, + * }; + * + * // Allocate a new netlink message, type=RTM_SETLINK, flags=NLM_F_ECHO + * if (!(msg = nlmsg_alloc_simple(RTM_SETLINK, NLM_F_ECHO))) + * return NULL; + * + * // Append the family specific header (struct ifinfomsg) + * if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0) + * goto nla_put_failure + * + * // Append a 32 bit integer attribute to carry the MTU + * NLA_PUT_U32(msg, IFLA_MTU, mtu); + * + * // Append a unspecific attribute to carry the link layer address + * NLA_PUT_ADDR(msg, IFLA_ADDRESS, lladdr); + * + * // Append a container for nested attributes to carry link information + * if (!(info = nla_nest_start(msg, IFLA_LINKINFO))) + * goto nla_put_failure; + * + * // Put a string attribute into the container + * NLA_PUT_STRING(msg, IFLA_INFO_KIND, "vlan"); + * + * // Append another container inside the open container to carry + * // vlan specific attributes + * if (!(vlan = nla_nest_start(msg, IFLA_INFO_DATA))) + * goto nla_put_failure; + * + * // add vlan specific info attributes here... + * + * // Finish nesting the vlan attributes and close the second container. + * nla_nest_end(msg, vlan); + * + * // Finish nesting the link info attribute and close the first container. + * nla_nest_end(msg, info); + * + * return msg; + * + * // If any of the construction macros fails, we end up here. + * nla_put_failure: + * nlmsg_free(msg); + * return NULL; + * } + * @endcode + * + * @par Example 2.1 Parsing a netlink message with attributes. + * @code + * int parse_message(struct nl_msg *msg) + * { + * // The policy defines two attributes: a 32 bit integer and a container + * // for nested attributes. + * struct nla_policy attr_policy[ATTR_MAX+1] = { + * [ATTR_FOO] = { .type = NLA_U32 }, + * [ATTR_BAR] = { .type = NLA_NESTED }, + * }; + * struct nlattr *attrs[ATTR_MAX+1]; + * int err; + * + * // The nlmsg_parse() function will make sure that the message contains + * // enough payload to hold the header (struct my_hdr), validates any + * // attributes attached to the messages and stores a pointer to each + * // attribute in the attrs[] array accessable by attribute type. + * if ((err = nlmsg_parse(nlmsg_hdr(msg), sizeof(struct my_hdr), attrs, + * ATTR_MAX, attr_policy)) < 0) + * goto errout; + * + * if (attrs[ATTR_FOO]) { + * // It is safe to directly access the attribute payload without + * // any further checks since nlmsg_parse() enforced the policy. + * uint32_t foo = nla_get_u32(attrs[ATTR_FOO]); + * } + * + * if (attrs[ATTR_BAR]) { + * struct nlattr *nested[NESTED_MAX+1]; + * + * // Attributes nested in a container can be parsed the same way + * // as top level attributes. + * if ((err = nla_parse_nested(nested, NESTED_MAX, attrs[ATTR_BAR], + * nested_policy)) < 0) + * goto errout; + * + * // Process nested attributes here. + * } + * + * err = 0; + * errout: + * return err; + * } + * @endcode + * + * @{ + */ + +/** + * @name Attribute Size Calculation + * @{ + */ + +/** + * Return size of attribute whithout padding. + * @arg payload Payload length of attribute. + * + * @code + * <-------- nla_attr_size(payload) ---------> + * +------------------+- - -+- - - - - - - - - +- - -+ + * | Attribute Header | Pad | Payload | Pad | + * +------------------+- - -+- - - - - - - - - +- - -+ + * @endcode + * + * @return Size of attribute in bytes without padding. + */ +int nla_attr_size(int payload) +{ + return NLA_HDRLEN + payload; +} + +/** + * Return size of attribute including padding. + * @arg payload Payload length of attribute. + * + * @code + * <----------- nla_total_size(payload) -----------> + * +------------------+- - -+- - - - - - - - - +- - -+ + * | Attribute Header | Pad | Payload | Pad | + * +------------------+- - -+- - - - - - - - - +- - -+ + * @endcode + * + * @return Size of attribute in bytes. + */ +int nla_total_size(int payload) +{ + return NLA_ALIGN(nla_attr_size(payload)); +} + +/** + * Return length of padding at the tail of the attribute. + * @arg payload Payload length of attribute. + * + * @code + * +------------------+- - -+- - - - - - - - - +- - -+ + * | Attribute Header | Pad | Payload | Pad | + * +------------------+- - -+- - - - - - - - - +- - -+ + * <---> + * @endcode + * + * @return Length of padding in bytes. + */ +int nla_padlen(int payload) +{ + return nla_total_size(payload) - nla_attr_size(payload); +} + +/** @} */ + +/** + * @name Parsing Attributes + * @{ + */ + +/** + * Return type of the attribute. + * @arg nla Attribute. + * + * @return Type of attribute. + */ +int nla_type(const struct nlattr *nla) +{ + return nla->nla_type & NLA_TYPE_MASK; +} + +/** + * Return pointer to the payload section. + * @arg nla Attribute. + * + * @return Pointer to start of payload section. + */ +void *nla_data(const struct nlattr *nla) +{ + return (char *) nla + NLA_HDRLEN; +} + +/** + * Return length of the payload . + * @arg nla Attribute + * + * @return Length of payload in bytes. + */ +int nla_len(const struct nlattr *nla) +{ + return nla->nla_len - NLA_HDRLEN; +} + +/** + * Check if the attribute header and payload can be accessed safely. + * @arg nla Attribute of any kind. + * @arg remaining Number of bytes remaining in attribute stream. + * + * Verifies that the header and payload do not exceed the number of + * bytes left in the attribute stream. This function must be called + * before access the attribute header or payload when iterating over + * the attribute stream using nla_next(). + * + * @return True if the attribute can be accessed safely, false otherwise. + */ +int nla_ok(const struct nlattr *nla, int remaining) +{ + return remaining >= sizeof(*nla) && + nla->nla_len >= sizeof(*nla) && + nla->nla_len <= remaining; +} + +/** + * Return next attribute in a stream of attributes. + * @arg nla Attribute of any kind. + * @arg remaining Variable to count remaining bytes in stream. + * + * Calculates the offset to the next attribute based on the attribute + * given. The attribute provided is assumed to be accessible, the + * caller is responsible to use nla_ok() beforehand. The offset (length + * of specified attribute including padding) is then subtracted from + * the remaining bytes variable and a pointer to the next attribute is + * returned. + * + * nla_next() can be called as long as remainig is >0. + * + * @return Pointer to next attribute. + */ +struct nlattr *nla_next(const struct nlattr *nla, int *remaining) +{ + int totlen = NLA_ALIGN(nla->nla_len); + + *remaining -= totlen; + return (struct nlattr *) ((char *) nla + totlen); +} + +static uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = { + [NLA_U8] = sizeof(uint8_t), + [NLA_U16] = sizeof(uint16_t), + [NLA_U32] = sizeof(uint32_t), + [NLA_U64] = sizeof(uint64_t), + [NLA_STRING] = 1, +}; + +static int validate_nla(struct nlattr *nla, int maxtype, + struct nla_policy *policy) +{ + struct nla_policy *pt; + int minlen = 0, type = nla_type(nla); + + if (type <= 0 || type > maxtype) + return 0; + + pt = &policy[type]; + + if (pt->type > NLA_TYPE_MAX) + BUG(); + + if (pt->minlen) + minlen = pt->minlen; + else if (pt->type != NLA_UNSPEC) + minlen = nla_attr_minlen[pt->type]; + + if (pt->type == NLA_FLAG && nla_len(nla) > 0) + return -NLE_RANGE; + + if (nla_len(nla) < minlen) + return -NLE_RANGE; + + if (pt->maxlen && nla_len(nla) > pt->maxlen) + return -NLE_RANGE; + + if (pt->type == NLA_STRING) { + char *data = nla_data(nla); + if (data[nla_len(nla) - 1] != '\0') + return -NLE_INVAL; + } + + return 0; +} + + +/** + * Create attribute index based on a stream of attributes. + * @arg tb Index array to be filled (maxtype+1 elements). + * @arg maxtype Maximum attribute type expected and accepted. + * @arg head Head of attribute stream. + * @arg len Length of attribute stream. + * @arg policy Attribute validation policy. + * + * Iterates over the stream of attributes and stores a pointer to each + * attribute in the index array using the attribute type as index to + * the array. Attribute with a type greater than the maximum type + * specified will be silently ignored in order to maintain backwards + * compatibility. If \a policy is not NULL, the attribute will be + * validated using the specified policy. + * + * @see nla_validate + * @return 0 on success or a negative error code. + */ +int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, + struct nla_policy *policy) +{ + struct nlattr *nla; + int rem, err; + + memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); + + nla_for_each_attr(nla, head, len, rem) { + int type = nla_type(nla); + + if (type == 0) { + fprintf(stderr, "Illegal nla->nla_type == 0\n"); + continue; + } + + if (type <= maxtype) { + if (policy) { + err = validate_nla(nla, maxtype, policy); + if (err < 0) + goto errout; + } + + tb[type] = nla; + } + } + + if (rem > 0) + fprintf(stderr, "netlink: %d bytes leftover after parsing " + "attributes.\n", rem); + + err = 0; +errout: + return err; +} + +/** + * Validate a stream of attributes. + * @arg head Head of attributes stream. + * @arg len Length of attributes stream. + * @arg maxtype Maximum attribute type expected and accepted. + * @arg policy Validation policy. + * + * Iterates over the stream of attributes and validates each attribute + * one by one using the specified policy. Attributes with a type greater + * than the maximum type specified will be silently ignored in order to + * maintain backwards compatibility. + * + * See \ref attr_datatypes for more details on what kind of validation + * checks are performed on each attribute data type. + * + * @return 0 on success or a negative error code. + */ +int nla_validate(struct nlattr *head, int len, int maxtype, + struct nla_policy *policy) +{ + struct nlattr *nla; + int rem, err; + + nla_for_each_attr(nla, head, len, rem) { + err = validate_nla(nla, maxtype, policy); + if (err < 0) + goto errout; + } + + err = 0; +errout: + return err; +} + +/** + * Find a single attribute in a stream of attributes. + * @arg head Head of attributes stream. + * @arg len Length of attributes stream. + * @arg attrtype Attribute type to look for. + * + * Iterates over the stream of attributes and compares each type with + * the type specified. Returns the first attribute which matches the + * type. + * + * @return Pointer to attribute found or NULL. + */ +struct nlattr *nla_find(struct nlattr *head, int len, int attrtype) +{ + struct nlattr *nla; + int rem; + + nla_for_each_attr(nla, head, len, rem) + if (nla_type(nla) == attrtype) + return nla; + + return NULL; +} + +/** @} */ + +/** + * @name Helper Functions + * @{ + */ + +/** + * Copy attribute payload to another memory area. + * @arg dest Pointer to destination memory area. + * @arg src Attribute + * @arg count Number of bytes to copy at most. + * + * Note: The number of bytes copied is limited by the length of + * the attribute payload. + * + * @return The number of bytes copied to dest. + */ +int nla_memcpy(void *dest, struct nlattr *src, int count) +{ + int minlen; + + if (!src) + return 0; + + minlen = min_t(int, count, nla_len(src)); + memcpy(dest, nla_data(src), minlen); + + return minlen; +} + +/** + * Copy string attribute payload to a buffer. + * @arg dst Pointer to destination buffer. + * @arg nla Attribute of type NLA_STRING. + * @arg dstsize Size of destination buffer in bytes. + * + * Copies at most dstsize - 1 bytes to the destination buffer. + * The result is always a valid NUL terminated string. Unlike + * strlcpy the destination buffer is always padded out. + * + * @return The length of string attribute without the terminating NUL. + */ +size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize) +{ + size_t srclen = nla_len(nla); + char *src = nla_data(nla); + + if (srclen > 0 && src[srclen - 1] == '\0') + srclen--; + + if (dstsize > 0) { + size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen; + + memset(dst, 0, dstsize); + memcpy(dst, src, len); + } + + return srclen; +} + +/** + * Compare attribute payload with memory area. + * @arg nla Attribute. + * @arg data Memory area to compare to. + * @arg size Number of bytes to compare. + * + * @see memcmp(3) + * @return An integer less than, equal to, or greater than zero. + */ +int nla_memcmp(const struct nlattr *nla, const void *data, size_t size) +{ + int d = nla_len(nla) - size; + + if (d == 0) + d = memcmp(nla_data(nla), data, size); + + return d; +} + +/** + * Compare string attribute payload with string + * @arg nla Attribute of type NLA_STRING. + * @arg str NUL terminated string. + * + * @see strcmp(3) + * @return An integer less than, equal to, or greater than zero. + */ +int nla_strcmp(const struct nlattr *nla, const char *str) +{ + int len = strlen(str) + 1; + int d = nla_len(nla) - len; + + if (d == 0) + d = memcmp(nla_data(nla), str, len); + + return d; +} + +/** @} */ + +/** + * @name Unspecific Attribute + * @{ + */ + +/** + * Reserve space for a attribute. + * @arg msg Netlink Message. + * @arg attrtype Attribute Type. + * @arg attrlen Length of payload. + * + * Reserves room for a attribute in the specified netlink message and + * fills in the attribute header (type, length). Returns NULL if there + * is unsuficient space for the attribute. + * + * Any padding between payload and the start of the next attribute is + * zeroed out. + * + * @return Pointer to start of attribute or NULL on failure. + */ +struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int attrlen) +{ + struct nlattr *nla; + int tlen; + + tlen = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) + nla_total_size(attrlen); + + if ((tlen + msg->nm_nlh->nlmsg_len) > msg->nm_size) + return NULL; + + nla = (struct nlattr *) nlmsg_tail(msg->nm_nlh); + nla->nla_type = attrtype; + nla->nla_len = nla_attr_size(attrlen); + + if (attrlen) + memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen)); + msg->nm_nlh->nlmsg_len = tlen; + + NL_DBG(2, "msg %p: attr <%p> %d: Reserved %d (%d) bytes at offset +%td " + "nlmsg_len=%d\n", msg, nla, nla->nla_type, + nla_total_size(attrlen), attrlen, + (void *) nla - nlmsg_data(msg->nm_nlh), + msg->nm_nlh->nlmsg_len); + + return nla; +} + +/** + * Add a unspecific attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg datalen Length of data to be used as payload. + * @arg data Pointer to data to be used as attribute payload. + * + * Reserves room for a unspecific attribute and copies the provided data + * into the message as payload of the attribute. Returns an error if there + * is insufficient space for the attribute. + * + * @see nla_reserve + * @return 0 on success or a negative error code. + */ +int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data) +{ + struct nlattr *nla; + + nla = nla_reserve(msg, attrtype, datalen); + if (!nla) + return -NLE_NOMEM; + + if (datalen > 0) { + memcpy(nla_data(nla), data, datalen); + NL_DBG(2, "msg %p: attr <%p> %d: Wrote %d bytes at offset +%td\n", + msg, nla, nla->nla_type, datalen, + (void *) nla - nlmsg_data(msg->nm_nlh)); + } + + return 0; +} + +/** + * Add abstract data as unspecific attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg data Abstract data object. + * + * Equivalent to nla_put() except that the length of the payload is + * derived from the abstract data object. + * + * @see nla_put + * @return 0 on success or a negative error code. + */ +int nla_put_data(struct nl_msg *msg, int attrtype, struct nl_data *data) +{ + return nla_put(msg, attrtype, nl_data_get_size(data), + nl_data_get(data)); +} + +/** + * Add abstract address as unspecific attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg addr Abstract address object. + * + * @see nla_put + * @return 0 on success or a negative error code. + */ +int nla_put_addr(struct nl_msg *msg, int attrtype, struct nl_addr *addr) +{ + return nla_put(msg, attrtype, nl_addr_get_len(addr), + nl_addr_get_binary_addr(addr)); +} + +/** @} */ + +/** + * @name Integer Attributes + */ + +/** + * Add 8 bit integer attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value Numeric value to store as payload. + * + * @see nla_put + * @return 0 on success or a negative error code. + */ +int nla_put_u8(struct nl_msg *msg, int attrtype, uint8_t value) +{ + return nla_put(msg, attrtype, sizeof(uint8_t), &value); +} + +/** + * Return value of 8 bit integer attribute. + * @arg nla 8 bit integer attribute + * + * @return Payload as 8 bit integer. + */ +uint8_t nla_get_u8(struct nlattr *nla) +{ + return *(uint8_t *) nla_data(nla); +} + +/** + * Add 16 bit integer attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value Numeric value to store as payload. + * + * @see nla_put + * @return 0 on success or a negative error code. + */ +int nla_put_u16(struct nl_msg *msg, int attrtype, uint16_t value) +{ + return nla_put(msg, attrtype, sizeof(uint16_t), &value); +} + +/** + * Return payload of 16 bit integer attribute. + * @arg nla 16 bit integer attribute + * + * @return Payload as 16 bit integer. + */ +uint16_t nla_get_u16(struct nlattr *nla) +{ + return *(uint16_t *) nla_data(nla); +} + +/** + * Add 32 bit integer attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value Numeric value to store as payload. + * + * @see nla_put + * @return 0 on success or a negative error code. + */ +int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value) +{ + return nla_put(msg, attrtype, sizeof(uint32_t), &value); +} + +/** + * Return payload of 32 bit integer attribute. + * @arg nla 32 bit integer attribute. + * + * @return Payload as 32 bit integer. + */ +uint32_t nla_get_u32(struct nlattr *nla) +{ + return *(uint32_t *) nla_data(nla); +} + +/** + * Add 64 bit integer attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value Numeric value to store as payload. + * + * @see nla_put + * @return 0 on success or a negative error code. + */ +int nla_put_u64(struct nl_msg *msg, int attrtype, uint64_t value) +{ + return nla_put(msg, attrtype, sizeof(uint64_t), &value); +} + +/** + * Return payload of u64 attribute + * @arg nla u64 netlink attribute + * + * @return Payload as 64 bit integer. + */ +uint64_t nla_get_u64(struct nlattr *nla) +{ + uint64_t tmp; + + nla_memcpy(&tmp, nla, sizeof(tmp)); + + return tmp; +} + +/** @} */ + +/** + * @name String Attribute + */ + +/** + * Add string attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg str NUL terminated string. + * + * @see nla_put + * @return 0 on success or a negative error code. + */ +int nla_put_string(struct nl_msg *msg, int attrtype, const char *str) +{ + return nla_put(msg, attrtype, strlen(str) + 1, str); +} + +/** + * Return payload of string attribute. + * @arg nla String attribute. + * + * @return Pointer to attribute payload. + */ +char *nla_get_string(struct nlattr *nla) +{ + return (char *) nla_data(nla); +} + +char *nla_strdup(struct nlattr *nla) +{ + return strdup(nla_get_string(nla)); +} + +/** @} */ + +/** + * @name Flag Attribute + */ + +/** + * Add flag netlink attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * + * @see nla_put + * @return 0 on success or a negative error code. + */ +int nla_put_flag(struct nl_msg *msg, int attrtype) +{ + return nla_put(msg, attrtype, 0, NULL); +} + +/** + * Return true if flag attribute is set. + * @arg nla Flag netlink attribute. + * + * @return True if flag is set, otherwise false. + */ +int nla_get_flag(struct nlattr *nla) +{ + return !!nla; +} + +/** @} */ + +/** + * @name Microseconds Attribute + */ + +/** + * Add a msecs netlink attribute to a netlink message + * @arg n netlink message + * @arg attrtype attribute type + * @arg msecs number of msecs + */ +int nla_put_msecs(struct nl_msg *n, int attrtype, unsigned long msecs) +{ + return nla_put_u64(n, attrtype, msecs); +} + +/** + * Return payload of msecs attribute + * @arg nla msecs netlink attribute + * + * @return the number of milliseconds. + */ +unsigned long nla_get_msecs(struct nlattr *nla) +{ + return nla_get_u64(nla); +} + +/** @} */ + +/** + * @name Nested Attribute + */ + +/** + * Add nested attributes to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg nested Message containing attributes to be nested. + * + * Takes the attributes found in the \a nested message and appends them + * to the message \a msg nested in a container of the type \a attrtype. + * The \a nested message may not have a family specific header. + * + * @see nla_put + * @return 0 on success or a negative error code. + */ +int nla_put_nested(struct nl_msg *msg, int attrtype, struct nl_msg *nested) +{ + NL_DBG(2, "msg %p: attr <> %d: adding msg %p as nested attribute\n", + msg, attrtype, nested); + + return nla_put(msg, attrtype, nlmsg_datalen(nested->nm_nlh), + nlmsg_data(nested->nm_nlh)); +} + + +/** + * Start a new level of nested attributes. + * @arg msg Netlink message. + * @arg attrtype Attribute type of container. + * + * @return Pointer to container attribute. + */ +struct nlattr *nla_nest_start(struct nl_msg *msg, int attrtype) +{ + struct nlattr *start = (struct nlattr *) nlmsg_tail(msg->nm_nlh); + + if (nla_put(msg, attrtype, 0, NULL) < 0) + return NULL; + + NL_DBG(2, "msg %p: attr <%p> %d: starting nesting\n", + msg, start, start->nla_type); + + return start; +} + +/** + * Finalize nesting of attributes. + * @arg msg Netlink message. + * @arg start Container attribute as returned from nla_nest_start(). + * + * Corrects the container attribute header to include the appeneded attributes. + * + * @return 0 + */ +int nla_nest_end(struct nl_msg *msg, struct nlattr *start) +{ + size_t pad, len; + + len = (void *) nlmsg_tail(msg->nm_nlh) - (void *) start; + + if (len == NLA_HDRLEN) { + /* + * Kernel can't handle empty nested attributes, trim the + * attribute header again + */ + msg->nm_nlh->nlmsg_len -= NLA_HDRLEN; + memset(nlmsg_tail(msg->nm_nlh), 0, NLA_HDRLEN); + + return 0; + } + + start->nla_len = len; + + pad = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len; + if (pad > 0) { + /* + * Data inside attribute does not end at a alignment boundry. + * Pad accordingly and accoun for the additional space in + * the message. nlmsg_reserve() may never fail in this situation, + * the allocate message buffer must be a multiple of NLMSG_ALIGNTO. + */ + if (!nlmsg_reserve(msg, pad, 0)) + BUG(); + + NL_DBG(2, "msg %p: attr <%p> %d: added %zu bytes of padding\n", + msg, start, start->nla_type, pad); + } + + NL_DBG(2, "msg %p: attr <%p> %d: closing nesting, len=%u\n", + msg, start, start->nla_type, start->nla_len); + + return 0; +} + +/** + * Create attribute index based on nested attribute + * @arg tb Index array to be filled (maxtype+1 elements). + * @arg maxtype Maximum attribute type expected and accepted. + * @arg nla Nested Attribute. + * @arg policy Attribute validation policy. + * + * Feeds the stream of attributes nested into the specified attribute + * to nla_parse(). + * + * @see nla_parse + * @return 0 on success or a negative error code. + */ +int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, + struct nla_policy *policy) +{ + return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy); +} + +/** @} */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/cache.c b/libnetwork/libnl3/lib/cache.c new file mode 100644 index 0000000..a1c8eae --- /dev/null +++ b/libnetwork/libnl3/lib/cache.c @@ -0,0 +1,965 @@ +/* + * lib/cache.c Caching Module + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup cache_mngt + * @defgroup cache Cache + * + * @code + * Cache Management | | Type Specific Cache Operations + * + * | | +----------------+ +------------+ + * | request update | | msg_parser | + * | | +----------------+ +------------+ + * +- - - - -^- - - - - - - -^- -|- - - - + * nl_cache_update: | | | | + * 1) --------- co_request_update ------+ | | + * | | | + * 2) destroy old cache +----------- pp_cb ---------|---+ + * | | | + * 3) ---------- nl_recvmsgs ----------+ +- cb_valid -+ + * +--------------+ | | | | + * | nl_cache_add |<-----+ + - - -v- -|- - - - - - - - - - - + * +--------------+ | | +-------------+ + * | nl_recvmsgs | + * | | +-----|-^-----+ + * +---v-|---+ + * | | | nl_recv | + * +---------+ + * | | Core Netlink + * @endcode + * + * @{ + */ + +#include +#include +#include +#include +#include + +/** + * @name Access Functions + * @{ + */ + +/** + * Return the number of items in the cache + * @arg cache cache handle + */ +int nl_cache_nitems(struct nl_cache *cache) +{ + return cache->c_nitems; +} + +/** + * Return the number of items matching a filter in the cache + * @arg cache Cache object. + * @arg filter Filter object. + */ +int nl_cache_nitems_filter(struct nl_cache *cache, struct nl_object *filter) +{ + struct nl_object *obj; + int nitems = 0; + + if (cache->c_ops == NULL) + BUG(); + + nl_list_for_each_entry(obj, &cache->c_items, ce_list) { + if (filter && !nl_object_match_filter(obj, filter)) + continue; + + nitems++; + } + + return nitems; +} + +/** + * Returns \b true if the cache is empty. + * @arg cache Cache to check + * @return \a true if the cache is empty, otherwise \b false is returned. + */ +int nl_cache_is_empty(struct nl_cache *cache) +{ + return nl_list_empty(&cache->c_items); +} + +/** + * Return the operations set of the cache + * @arg cache cache handle + */ +struct nl_cache_ops *nl_cache_get_ops(struct nl_cache *cache) +{ + return cache->c_ops; +} + +/** + * Return the first element in the cache + * @arg cache cache handle + */ +struct nl_object *nl_cache_get_first(struct nl_cache *cache) +{ + if (nl_list_empty(&cache->c_items)) + return NULL; + + return nl_list_entry(cache->c_items.next, + struct nl_object, ce_list); +} + +/** + * Return the last element in the cache + * @arg cache cache handle + */ +struct nl_object *nl_cache_get_last(struct nl_cache *cache) +{ + if (nl_list_empty(&cache->c_items)) + return NULL; + + return nl_list_entry(cache->c_items.prev, + struct nl_object, ce_list); +} + +/** + * Return the next element in the cache + * @arg obj current object + */ +struct nl_object *nl_cache_get_next(struct nl_object *obj) +{ + if (nl_list_at_tail(obj, &obj->ce_cache->c_items, ce_list)) + return NULL; + else + return nl_list_entry(obj->ce_list.next, + struct nl_object, ce_list); +} + +/** + * Return the previous element in the cache + * @arg obj current object + */ +struct nl_object *nl_cache_get_prev(struct nl_object *obj) +{ + if (nl_list_at_head(obj, &obj->ce_cache->c_items, ce_list)) + return NULL; + else + return nl_list_entry(obj->ce_list.prev, + struct nl_object, ce_list); +} + +/** @} */ + +/** + * @name Cache Allocation/Deletion + * @{ + */ + +/** + * Allocate new cache + * @arg ops Cache operations + * + * Allocate and initialize a new cache based on the cache operations + * provided. + * + * @return Allocated cache or NULL if allocation failed. + */ +struct nl_cache *nl_cache_alloc(struct nl_cache_ops *ops) +{ + struct nl_cache *cache; + + cache = calloc(1, sizeof(*cache)); + if (!cache) + return NULL; + + nl_init_list_head(&cache->c_items); + cache->c_ops = ops; + + NL_DBG(2, "Allocated cache %p <%s>.\n", cache, nl_cache_name(cache)); + + return cache; +} + +/** + * Allocate new cache and fill it + * @arg ops Cache operations + * @arg sock Netlink socket + * @arg result Result pointer + * + * Allocate new cache and fill it. Equivalent to calling: + * @code + * cache = nl_cache_alloc(ops); + * nl_cache_refill(sock, cache); + * @endcode + * + * @see nl_cache_alloc + * + * @return 0 on success or a negative error code. + */ +int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock, + struct nl_cache **result) +{ + struct nl_cache *cache; + int err; + + if (!(cache = nl_cache_alloc(ops))) + return -NLE_NOMEM; + + if (sock && (err = nl_cache_refill(sock, cache)) < 0) { + nl_cache_free(cache); + return err; + } + + *result = cache; + return 0; +} + +/** + * Allocate new cache based on type name + * @arg kind Name of cache type + * @arg result Result pointer + * + * Lookup cache ops via nl_cache_ops_lookup() and allocate the cache + * by calling nl_cache_alloc(). Stores the allocated cache in the + * result pointer provided. + * + * @see nl_cache_alloc + * + * @return 0 on success or a negative error code. + */ +int nl_cache_alloc_name(const char *kind, struct nl_cache **result) +{ + struct nl_cache_ops *ops; + struct nl_cache *cache; + + ops = nl_cache_ops_lookup(kind); + if (!ops) + return -NLE_NOCACHE; + + if (!(cache = nl_cache_alloc(ops))) + return -NLE_NOMEM; + + *result = cache; + return 0; +} + +/** + * Allocate new cache containing a subset of an existing cache + * @arg orig Original cache to base new cache on + * @arg filter Filter defining the subset to be filled into the new cache + * + * Allocates a new cache matching the type of the cache specified by + * \p orig. Iterates over the \p orig cache applying the specified + * \p filter and copies all objects that match to the new cache. + * + * The copied objects are clones but do not contain a reference to each + * other. Later modifications to objects in the original cache will + * not affect objects in the new cache. + * + * @return A newly allocated cache or NULL. + */ +struct nl_cache *nl_cache_subset(struct nl_cache *orig, + struct nl_object *filter) +{ + struct nl_cache *cache; + struct nl_object *obj; + + if (!filter) + BUG(); + + cache = nl_cache_alloc(orig->c_ops); + if (!cache) + return NULL; + + nl_list_for_each_entry(obj, &orig->c_items, ce_list) { + if (!nl_object_match_filter(obj, filter)) + continue; + + nl_cache_add(cache, obj); + } + + return cache; +} + +/** + * Remove all objects of a cache. + * @arg cache Cache to clear + * + * The objects are unliked/removed from the cache by calling + * nl_cache_remove() on each object in the cache. If any of the objects + * to not contain any further references to them, those objects will + * be freed. + * + * Unlike with nl_cache_free(), the cache is not freed just emptied. + */ +void nl_cache_clear(struct nl_cache *cache) +{ + struct nl_object *obj, *tmp; + + NL_DBG(1, "Clearing cache %p <%s>...\n", cache, nl_cache_name(cache)); + + nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) + nl_cache_remove(obj); +} + +/** + * Free a cache. + * @arg cache Cache to free. + * + * Calls nl_cache_clear() to remove all objects associated with the + * cache and frees the cache afterwards. + * + * @see nl_cache_clear() + */ +void nl_cache_free(struct nl_cache *cache) +{ + if (!cache) + return; + + nl_cache_clear(cache); + NL_DBG(1, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache)); + free(cache); +} + +/** @} */ + +/** + * @name Cache Modifications + * @{ + */ + +static int __cache_add(struct nl_cache *cache, struct nl_object *obj) +{ + obj->ce_cache = cache; + + nl_list_add_tail(&obj->ce_list, &cache->c_items); + cache->c_nitems++; + + NL_DBG(1, "Added %p to cache %p <%s>.\n", + obj, cache, nl_cache_name(cache)); + + return 0; +} + +/** + * Add object to cache. + * @arg cache Cache + * @arg obj Object to be added to the cache + * + * Adds the object \p obj to the specified \p cache. In case the object + * is already associated with another cache, the object is cloned before + * adding it to the cache. In this case, the sole reference to the object + * will be the one of the cache. Therefore clearing/freeing the cache + * will result in the object being freed again. + * + * If the object has not been associated with a cache yet, the reference + * counter of the object is incremented to account for the additional + * reference. + * + * The type of the object and cache must match, otherwise an error is + * returned (-NLE_OBJ_MISMATCH). + * + * @see nl_cache_move() + * + * @return 0 or a negative error code. + */ +int nl_cache_add(struct nl_cache *cache, struct nl_object *obj) +{ + struct nl_object *new; + + if (cache->c_ops->co_obj_ops != obj->ce_ops) + return -NLE_OBJ_MISMATCH; + + if (!nl_list_empty(&obj->ce_list)) { + new = nl_object_clone(obj); + if (!new) + return -NLE_NOMEM; + } else { + nl_object_get(obj); + new = obj; + } + + return __cache_add(cache, new); +} + +/** + * Move object from one cache to another + * @arg cache Cache to move object to. + * @arg obj Object subject to be moved + * + * Removes the the specified object \p obj from its associated cache + * and moves it to another cache. + * + * If the object is not associated with a cache, the function behaves + * just like nl_cache_add(). + * + * The type of the object and cache must match, otherwise an error is + * returned (-NLE_OBJ_MISMATCH). + * + * @see nl_cache_add() + * + * @return 0 on success or a negative error code. + */ +int nl_cache_move(struct nl_cache *cache, struct nl_object *obj) +{ + if (cache->c_ops->co_obj_ops != obj->ce_ops) + return -NLE_OBJ_MISMATCH; + + NL_DBG(3, "Moving object %p to cache %p\n", obj, cache); + + /* Acquire reference, if already in a cache this will be + * reverted during removal */ + nl_object_get(obj); + + if (!nl_list_empty(&obj->ce_list)) + nl_cache_remove(obj); + + return __cache_add(cache, obj); +} + +/** + * Remove object from cache. + * @arg obj Object to remove from cache + * + * Removes the object \c obj from the cache it is associated with. The + * reference counter of the object will be decremented. If the reference + * to the object was the only one remaining, the object will be freed. + * + * If no cache is associated with the object, this function is a NOP. + */ +void nl_cache_remove(struct nl_object *obj) +{ + struct nl_cache *cache = obj->ce_cache; + + if (cache == NULL) + return; + + nl_list_del(&obj->ce_list); + obj->ce_cache = NULL; + nl_object_put(obj); + cache->c_nitems--; + + NL_DBG(1, "Deleted %p from cache %p <%s>.\n", + obj, cache, nl_cache_name(cache)); +} + +/** @} */ + +/** + * @name Synchronization + * @{ + */ + +/** + * Set synchronization arg1 of cache + * @arg cache Cache + * @arg arg argument + * + * Synchronization arguments are used to specify filters when + * requesting dumps from the kernel. + */ +void nl_cache_set_arg1(struct nl_cache *cache, int arg) +{ + cache->c_iarg1 = arg; +} + +/** + * Set synchronization arg2 of cache + * @arg cache Cache + * @arg arg argument + * + * Synchronization arguments are used to specify filters when + * requesting dumps from the kernel. + */ +void nl_cache_set_arg2(struct nl_cache *cache, int arg) +{ + cache->c_iarg2 = arg; +} + +/** + * Invoke the request-update operation + * @arg sk Netlink socket. + * @arg cache Cache + * + * This function causes the \e request-update function of the cache + * operations to be invoked. This usually causes a dump request to + * be sent over the netlink socket which triggers the kernel to dump + * all objects of a specific type to be dumped onto the netlink + * socket for pickup. + * + * The behaviour of this function depends on the implemenation of + * the \e request_update function of each individual type of cache. + * + * This function will not have any effects on the cache (unless the + * request_update implementation of the cache operations does so). + * + * Use nl_cache_pickup() to pick-up (read) the objects from the socket + * and fill them into the cache. + * + * @see nl_cache_pickup(), nl_cache_resync() + * + * @return 0 on success or a negative error code. + */ +static int nl_cache_request_full_dump(struct nl_sock *sk, + struct nl_cache *cache) +{ + NL_DBG(2, "Requesting dump from kernel for cache %p <%s>...\n", + cache, nl_cache_name(cache)); + + if (cache->c_ops->co_request_update == NULL) + return -NLE_OPNOTSUPP; + + return cache->c_ops->co_request_update(cache, sk); +} + +/** @cond SKIP */ +struct update_xdata { + struct nl_cache_ops *ops; + struct nl_parser_param *params; +}; + +static int update_msg_parser(struct nl_msg *msg, void *arg) +{ + struct update_xdata *x = arg; + + return nl_cache_parse(x->ops, &msg->nm_src, msg->nm_nlh, x->params); +} +/** @endcond */ + +/** + * Pick-up a netlink request-update with your own parser + * @arg sk Netlink socket + * @arg cache Cache + * @arg param Parser parameters + */ +static int __cache_pickup(struct nl_sock *sk, struct nl_cache *cache, + struct nl_parser_param *param) +{ + int err; + struct nl_cb *cb; + struct update_xdata x = { + .ops = cache->c_ops, + .params = param, + }; + + NL_DBG(1, "Picking up answer for cache %p <%s>...\n", + cache, nl_cache_name(cache)); + + cb = nl_cb_clone(sk->s_cb); + if (cb == NULL) + return -NLE_NOMEM; + + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, update_msg_parser, &x); + + err = nl_recvmsgs(sk, cb); + if (err < 0) + NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned " \ + "%d: %s", cache, nl_cache_name(cache), + err, nl_geterror(err)); + + nl_cb_put(cb); + + return err; +} + +static int pickup_cb(struct nl_object *c, struct nl_parser_param *p) +{ + return nl_cache_add((struct nl_cache *) p->pp_arg, c); +} + +/** + * Pickup a netlink dump response and put it into a cache. + * @arg sk Netlink socket. + * @arg cache Cache to put items into. + * + * Waits for netlink messages to arrive, parses them and puts them into + * the specified cache. + * + * @return 0 on success or a negative error code. + */ +int nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache) +{ + struct nl_parser_param p = { + .pp_cb = pickup_cb, + .pp_arg = cache, + }; + + return __cache_pickup(sk, cache, &p); +} + +static int cache_include(struct nl_cache *cache, struct nl_object *obj, + struct nl_msgtype *type, change_func_t cb, void *data) +{ + struct nl_object *old; + + switch (type->mt_act) { + case NL_ACT_NEW: + case NL_ACT_DEL: + old = nl_cache_search(cache, obj); + if (old) { + nl_cache_remove(old); + if (type->mt_act == NL_ACT_DEL) { + if (cb) + cb(cache, old, NL_ACT_DEL, data); + nl_object_put(old); + } + } + + if (type->mt_act == NL_ACT_NEW) { + nl_cache_move(cache, obj); + if (old == NULL && cb) + cb(cache, obj, NL_ACT_NEW, data); + else if (old) { + if (nl_object_diff(old, obj) && cb) + cb(cache, obj, NL_ACT_CHANGE, data); + + nl_object_put(old); + } + } + break; + default: + NL_DBG(2, "Unknown action associated to object %p\n", obj); + return 0; + } + + return 0; +} + +int nl_cache_include(struct nl_cache *cache, struct nl_object *obj, + change_func_t change_cb, void *data) +{ + struct nl_cache_ops *ops = cache->c_ops; + int i; + + if (ops->co_obj_ops != obj->ce_ops) + return -NLE_OBJ_MISMATCH; + + for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) + if (ops->co_msgtypes[i].mt_id == obj->ce_msgtype) + return cache_include(cache, obj, &ops->co_msgtypes[i], + change_cb, data); + + return -NLE_MSGTYPE_NOSUPPORT; +} + +static int resync_cb(struct nl_object *c, struct nl_parser_param *p) +{ + struct nl_cache_assoc *ca = p->pp_arg; + + return nl_cache_include(ca->ca_cache, c, ca->ca_change, ca->ca_change_data); +} + +int nl_cache_resync(struct nl_sock *sk, struct nl_cache *cache, + change_func_t change_cb, void *data) +{ + struct nl_object *obj, *next; + struct nl_cache_assoc ca = { + .ca_cache = cache, + .ca_change = change_cb, + .ca_change_data = data, + }; + struct nl_parser_param p = { + .pp_cb = resync_cb, + .pp_arg = &ca, + }; + int err; + + NL_DBG(1, "Resyncing cache %p <%s>...\n", cache, nl_cache_name(cache)); + +restart: + /* Mark all objects so we can see if some of them are obsolete */ + nl_cache_mark_all(cache); + + err = nl_cache_request_full_dump(sk, cache); + if (err < 0) + goto errout; + + err = __cache_pickup(sk, cache, &p); + if (err == -NLE_DUMP_INTR) + goto restart; + else if (err < 0) + goto errout; + + nl_list_for_each_entry_safe(obj, next, &cache->c_items, ce_list) { + if (nl_object_is_marked(obj)) { + nl_object_get(obj); + nl_cache_remove(obj); + if (change_cb) + change_cb(cache, obj, NL_ACT_DEL, data); + nl_object_put(obj); + } + } + + NL_DBG(1, "Finished resyncing %p <%s>\n", cache, nl_cache_name(cache)); + + err = 0; +errout: + return err; +} + +/** @} */ + +/** + * @name Parsing + * @{ + */ + +/** @cond SKIP */ +int nl_cache_parse(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *nlh, struct nl_parser_param *params) +{ + int i, err; + + if (!nlmsg_valid_hdr(nlh, ops->co_hdrsize)) + return -NLE_MSG_TOOSHORT; + + for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) { + if (ops->co_msgtypes[i].mt_id == nlh->nlmsg_type) { + err = ops->co_msg_parser(ops, who, nlh, params); + if (err != -NLE_OPNOTSUPP) + goto errout; + } + } + + + err = -NLE_MSGTYPE_NOSUPPORT; +errout: + return err; +} +/** @endcond */ + +/** + * Parse a netlink message and add it to the cache. + * @arg cache cache to add element to + * @arg msg netlink message + * + * Parses a netlink message by calling the cache specific message parser + * and adds the new element to the cache. + * + * @return 0 or a negative error code. + */ +int nl_cache_parse_and_add(struct nl_cache *cache, struct nl_msg *msg) +{ + struct nl_parser_param p = { + .pp_cb = pickup_cb, + .pp_arg = cache, + }; + + return nl_cache_parse(cache->c_ops, NULL, nlmsg_hdr(msg), &p); +} + +/** + * (Re)fill a cache with the contents in the kernel. + * @arg sk Netlink socket. + * @arg cache cache to update + * + * Clears the specified cache and fills it with the current state in + * the kernel. + * + * @return 0 or a negative error code. + */ +int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache) +{ + int err; + +restart: + err = nl_cache_request_full_dump(sk, cache); + if (err < 0) + return err; + + NL_DBG(2, "Upading cache %p <%s>, request sent, waiting for dump...\n", + cache, nl_cache_name(cache)); + nl_cache_clear(cache); + + err = nl_cache_pickup(sk, cache); + if (err == -NLE_DUMP_INTR) { + fprintf(stderr, "dump interrupted, restarting!\n"); + goto restart; + } + + return err; +} + +/** @} */ + +/** + * @name Utillities + * @{ + */ + +/** + * Search object in cache + * @arg cache Cache + * @arg needle Object to look for. + * + * Searches the cache for an object which matches the object \p needle. + * The function nl_object_identical() is used to determine if the + * objects match. If a matching object is found, the reference counter + * is incremented and the object is returned. + * + * Therefore, if an object is returned, the reference to the object + * must be returned by calling nl_object_put() after usage. + * + * @return Reference to object or NULL if not found. + */ +struct nl_object *nl_cache_search(struct nl_cache *cache, + struct nl_object *needle) +{ + struct nl_object *obj; + + nl_list_for_each_entry(obj, &cache->c_items, ce_list) { + if (nl_object_identical(obj, needle)) { + nl_object_get(obj); + return obj; + } + } + + return NULL; +} + +/** + * Mark all objects of a cache + * @arg cache Cache + * + * Marks all objects of a cache by calling nl_object_mark() on each + * object associated with the cache. + */ +void nl_cache_mark_all(struct nl_cache *cache) +{ + struct nl_object *obj; + + NL_DBG(2, "Marking all objects in cache %p <%s>...\n", + cache, nl_cache_name(cache)); + + nl_list_for_each_entry(obj, &cache->c_items, ce_list) + nl_object_mark(obj); +} + +/** @} */ + +/** + * @name Dumping + * @{ + */ + +/** + * Dump all elements of a cache. + * @arg cache cache to dump + * @arg params dumping parameters + * + * Dumps all elements of the \a cache to the file descriptor \a fd. + */ +void nl_cache_dump(struct nl_cache *cache, struct nl_dump_params *params) +{ + nl_cache_dump_filter(cache, params, NULL); +} + +/** + * Dump all elements of a cache (filtered). + * @arg cache cache to dump + * @arg params dumping parameters (optional) + * @arg filter filter object + * + * Dumps all elements of the \a cache to the file descriptor \a fd + * given they match the given filter \a filter. + */ +void nl_cache_dump_filter(struct nl_cache *cache, + struct nl_dump_params *params, + struct nl_object *filter) +{ + int type = params ? params->dp_type : NL_DUMP_DETAILS; + struct nl_object_ops *ops; + struct nl_object *obj; + + NL_DBG(2, "Dumping cache %p <%s> filter %p\n", + cache, nl_cache_name(cache), filter); + + if (type > NL_DUMP_MAX || type < 0) + BUG(); + + if (cache->c_ops == NULL) + BUG(); + + ops = cache->c_ops->co_obj_ops; + if (!ops->oo_dump[type]) + return; + + nl_list_for_each_entry(obj, &cache->c_items, ce_list) { + if (filter && !nl_object_match_filter(obj, filter)) + continue; + + NL_DBG(4, "Dumping object %p...\n", obj); + dump_from_ops(obj, params); + } +} + +/** @} */ + +/** + * @name Iterators + * @{ + */ + +/** + * Call a callback on each element of the cache. + * @arg cache cache to iterate on + * @arg cb callback function + * @arg arg argument passed to callback function + * + * Calls a callback function \a cb on each element of the \a cache. + * The argument \a arg is passed on the callback function. + */ +void nl_cache_foreach(struct nl_cache *cache, + void (*cb)(struct nl_object *, void *), void *arg) +{ + nl_cache_foreach_filter(cache, NULL, cb, arg); +} + +/** + * Call a callback on each element of the cache (filtered). + * @arg cache cache to iterate on + * @arg filter filter object + * @arg cb callback function + * @arg arg argument passed to callback function + * + * Calls a callback function \a cb on each element of the \a cache + * that matches the \a filter. The argument \a arg is passed on + * to the callback function. + */ +void nl_cache_foreach_filter(struct nl_cache *cache, struct nl_object *filter, + void (*cb)(struct nl_object *, void *), void *arg) +{ + struct nl_object *obj, *tmp; + + if (cache->c_ops == NULL) + BUG(); + + nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) { + if (filter) { + int diff = nl_object_match_filter(obj, filter); + + NL_DBG(3, "%p<->%p object difference: %x\n", + obj, filter, diff); + + if (!diff) + continue; + } + + /* Caller may hold obj for a long time */ + nl_object_get(obj); + + cb(obj, arg); + + nl_object_put(obj); + } +} + +/** @} */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/cache_mngr.c b/libnetwork/libnl3/lib/cache_mngr.c new file mode 100644 index 0000000..cf5a951 --- /dev/null +++ b/libnetwork/libnl3/lib/cache_mngr.c @@ -0,0 +1,391 @@ +/* + * lib/cache_mngr.c Cache Manager + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup cache_mngt + * @defgroup cache_mngr Manager + * @brief Helps keeping caches up to date. + * + * The purpose of a cache manager is to keep track of caches and + * automatically receive event notifications to keep the caches + * up to date with the kernel state. Each manager has exactly one + * netlink socket assigned which limits the scope of each manager + * to exactly one netlink family. Therefore all caches committed + * to a manager must be part of the same netlink family. Due to the + * nature of a manager, it is not possible to have a cache maintain + * two instances of the same cache type. The socket is subscribed + * to the event notification group of each cache and also put into + * non-blocking mode. Functions exist to poll() on the socket to + * wait for new events to be received. + * + * @code + * App libnl Kernel + * | | + * +-----------------+ [ notification, link change ] + * | | Cache Manager | | [ (IFF_UP | IFF_RUNNING) ] + * | | | + * | | +------------+| | | [ notification, new addr ] + * <-------|---| route/link |<-------(async)--+ [ 10.0.1.1/32 dev eth1 ] + * | | +------------+| | | + * | +------------+| | + * <---|---|---| route/addr |<------|-(async)--------------+ + * | +------------+| + * | | +------------+| | + * <-------|---| ... || + * | | +------------+| | + * +-----------------+ + * | | + * @endcode + * + * @par 1) Creating a new cache manager + * @code + * struct nl_cache_mngr *mngr; + * + * // Allocate a new cache manager for RTNETLINK and automatically + * // provide the caches added to the manager. + * mngr = nl_cache_mngr_alloc(NETLINK_ROUTE, NL_AUTO_PROVIDE); + * @endcode + * + * @par 2) Keep track of a cache + * @code + * struct nl_cache *cache; + * + * // Create a new cache for links/interfaces and ask the manager to + * // keep it up to date for us. This will trigger a full dump request + * // to initially fill the cache. + * cache = nl_cache_mngr_add(mngr, "route/link"); + * @endcode + * + * @par 3) Make the manager receive updates + * @code + * // Give the manager the ability to receive updates, will call poll() + * // with a timeout of 5 seconds. + * if (nl_cache_mngr_poll(mngr, 5000) > 0) { + * // Manager received at least one update, dump cache? + * nl_cache_dump(cache, ...); + * } + * @endcode + * + * @par 4) Release cache manager + * @code + * nl_cache_mngr_free(mngr); + * @endcode + * @{ + */ + +#include +#include +#include +#include + +static int include_cb(struct nl_object *obj, struct nl_parser_param *p) +{ + struct nl_cache_assoc *ca = p->pp_arg; + struct nl_cache_ops *ops = ca->ca_cache->c_ops; + + NL_DBG(2, "Including object %p into cache %p\n", obj, ca->ca_cache); +#ifdef NL_DEBUG + if (nl_debug >= 4) + nl_object_dump(obj, &nl_debug_dp); +#endif + + if (ops->co_event_filter) + if (ops->co_event_filter(ca->ca_cache, obj) != NL_OK) + return 0; + + return nl_cache_include(ca->ca_cache, obj, ca->ca_change, ca->ca_change_data); +} + +static int event_input(struct nl_msg *msg, void *arg) +{ + struct nl_cache_mngr *mngr = arg; + int protocol = nlmsg_get_proto(msg); + int type = nlmsg_hdr(msg)->nlmsg_type; + struct nl_cache_ops *ops; + int i, n; + struct nl_parser_param p = { + .pp_cb = include_cb, + }; + + NL_DBG(2, "Cache manager %p, handling new message %p as event\n", + mngr, msg); +#ifdef NL_DEBUG + if (nl_debug >= 4) + nl_msg_dump(msg, stderr); +#endif + + if (mngr->cm_protocol != protocol) + BUG(); + + for (i = 0; i < mngr->cm_nassocs; i++) { + if (mngr->cm_assocs[i].ca_cache) { + ops = mngr->cm_assocs[i].ca_cache->c_ops; + for (n = 0; ops->co_msgtypes[n].mt_id >= 0; n++) + if (ops->co_msgtypes[n].mt_id == type) + goto found; + } + } + + return NL_SKIP; + +found: + NL_DBG(2, "Associated message %p to cache %p\n", + msg, mngr->cm_assocs[i].ca_cache); + p.pp_arg = &mngr->cm_assocs[i]; + + return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p); +} + +/** + * Allocate new cache manager + * @arg sk Netlink socket. + * @arg protocol Netlink Protocol this manager is used for + * @arg flags Flags + * @arg result Result pointer + * + * @return 0 on success or a negative error code. + */ +int nl_cache_mngr_alloc(struct nl_sock *sk, int protocol, int flags, + struct nl_cache_mngr **result) +{ + struct nl_cache_mngr *mngr; + int err = -NLE_NOMEM; + + if (sk == NULL) + BUG(); + + mngr = calloc(1, sizeof(*mngr)); + if (!mngr) + goto errout; + + mngr->cm_handle = sk; + mngr->cm_nassocs = 32; + mngr->cm_protocol = protocol; + mngr->cm_flags = flags; + mngr->cm_assocs = calloc(mngr->cm_nassocs, + sizeof(struct nl_cache_assoc)); + if (!mngr->cm_assocs) + goto errout; + + nl_socket_modify_cb(mngr->cm_handle, NL_CB_VALID, NL_CB_CUSTOM, + event_input, mngr); + + /* Required to receive async event notifications */ + nl_socket_disable_seq_check(mngr->cm_handle); + + if ((err = nl_connect(mngr->cm_handle, protocol) < 0)) + goto errout; + + if ((err = nl_socket_set_nonblocking(mngr->cm_handle) < 0)) + goto errout; + + NL_DBG(1, "Allocated cache manager %p, protocol %d, %d caches\n", + mngr, protocol, mngr->cm_nassocs); + + *result = mngr; + return 0; + +errout: + nl_cache_mngr_free(mngr); + return err; +} + +/** + * Add cache responsibility to cache manager + * @arg mngr Cache manager. + * @arg name Name of cache to keep track of + * @arg cb Function to be called upon changes. + * @arg data Argument passed on to change callback + * @arg result Pointer to store added cache. + * + * Allocates a new cache of the specified type and adds it to the manager. + * The operation will trigger a full dump request from the kernel to + * initially fill the contents of the cache. The manager will subscribe + * to the notification group of the cache to keep track of any further + * changes. + * + * @return 0 on success or a negative error code. + */ +int nl_cache_mngr_add(struct nl_cache_mngr *mngr, const char *name, + change_func_t cb, void *data, struct nl_cache **result) +{ + struct nl_cache_ops *ops; + struct nl_cache *cache; + struct nl_af_group *grp; + int err, i; + + ops = nl_cache_ops_lookup(name); + if (!ops) + return -NLE_NOCACHE; + + if (ops->co_protocol != mngr->cm_protocol) + return -NLE_PROTO_MISMATCH; + + if (ops->co_groups == NULL) + return -NLE_OPNOTSUPP; + + for (i = 0; i < mngr->cm_nassocs; i++) + if (mngr->cm_assocs[i].ca_cache && + mngr->cm_assocs[i].ca_cache->c_ops == ops) + return -NLE_EXIST; + +retry: + for (i = 0; i < mngr->cm_nassocs; i++) + if (!mngr->cm_assocs[i].ca_cache) + break; + + if (i >= mngr->cm_nassocs) { + mngr->cm_nassocs += 16; + mngr->cm_assocs = realloc(mngr->cm_assocs, + mngr->cm_nassocs * + sizeof(struct nl_cache_assoc)); + if (mngr->cm_assocs == NULL) + return -NLE_NOMEM; + else { + NL_DBG(1, "Increased capacity of cache manager %p " \ + "to %d\n", mngr, mngr->cm_nassocs); + goto retry; + } + } + + cache = nl_cache_alloc(ops); + if (!cache) + return -NLE_NOMEM; + + for (grp = ops->co_groups; grp->ag_group; grp++) { + err = nl_socket_add_membership(mngr->cm_handle, grp->ag_group); + if (err < 0) + goto errout_free_cache; + } + + err = nl_cache_refill(mngr->cm_handle, cache); + if (err < 0) + goto errout_drop_membership; + + mngr->cm_assocs[i].ca_cache = cache; + mngr->cm_assocs[i].ca_change = cb; + mngr->cm_assocs[i].ca_change_data = data; + + if (mngr->cm_flags & NL_AUTO_PROVIDE) + nl_cache_mngt_provide(cache); + + NL_DBG(1, "Added cache %p <%s> to cache manager %p\n", + cache, nl_cache_name(cache), mngr); + + *result = cache; + return 0; + +errout_drop_membership: + for (grp = ops->co_groups; grp->ag_group; grp++) + nl_socket_drop_membership(mngr->cm_handle, grp->ag_group); +errout_free_cache: + nl_cache_free(cache); + + return err; +} + +/** + * Get file descriptor + * @arg mngr Cache Manager + * + * Get the file descriptor of the socket associated to the manager. + * This can be used to change socket options or monitor activity + * using poll()/select(). + */ +int nl_cache_mngr_get_fd(struct nl_cache_mngr *mngr) +{ + return nl_socket_get_fd(mngr->cm_handle); +} + +/** + * Check for event notifications + * @arg mngr Cache Manager + * @arg timeout Upper limit poll() will block, in milliseconds. + * + * Causes poll() to be called to check for new event notifications + * being available. Automatically receives and handles available + * notifications. + * + * This functionally is ideally called regularly during an idle + * period. + * + * @return A positive value if at least one update was handled, 0 + * for none, or a negative error code. + */ +int nl_cache_mngr_poll(struct nl_cache_mngr *mngr, int timeout) +{ + int ret; + struct pollfd fds = { + .fd = nl_socket_get_fd(mngr->cm_handle), + .events = POLLIN, + }; + + NL_DBG(3, "Cache manager %p, poll() fd %d\n", mngr, fds.fd); + ret = poll(&fds, 1, timeout); + NL_DBG(3, "Cache manager %p, poll() returned %d\n", mngr, ret); + if (ret < 0) + return -nl_syserr2nlerr(errno); + + if (ret == 0) + return 0; + + return nl_cache_mngr_data_ready(mngr); +} + +/** + * Receive available event notifications + * @arg mngr Cache manager + * + * This function can be called if the socket associated to the manager + * contains updates to be received. This function should not be used + * if nl_cache_mngr_poll() is used. + * + * @return A positive value if at least one update was handled, 0 + * for none, or a negative error code. + */ +int nl_cache_mngr_data_ready(struct nl_cache_mngr *mngr) +{ + int err; + + err = nl_recvmsgs_default(mngr->cm_handle); + if (err < 0) + return err; + + return 1; +} + +/** + * Free cache manager and all caches. + * @arg mngr Cache manager. + * + * Release all resources after usage of a cache manager. + */ +void nl_cache_mngr_free(struct nl_cache_mngr *mngr) +{ + int i; + + if (!mngr) + return; + + if (mngr->cm_handle) + nl_close(mngr->cm_handle); + + for (i = 0; i < mngr->cm_nassocs; i++) + if (mngr->cm_assocs[i].ca_cache) + nl_cache_free(mngr->cm_assocs[i].ca_cache); + + free(mngr->cm_assocs); + free(mngr); + + NL_DBG(1, "Cache manager %p freed\n", mngr); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/cache_mngt.c b/libnetwork/libnl3/lib/cache_mngt.c new file mode 100644 index 0000000..a9ecf27 --- /dev/null +++ b/libnetwork/libnl3/lib/cache_mngt.c @@ -0,0 +1,256 @@ +/* + * lib/cache_mngt.c Cache Management + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup core + * @defgroup cache_mngt Caching + * @{ + */ + +#include +#include +#include +#include + +static struct nl_cache_ops *cache_ops; + +/** + * @name Cache Operations Sets + * @{ + */ + +/** + * Lookup the set cache operations of a certain cache type + * @arg name name of the cache type + * + * @return The cache operations or NULL if no operations + * have been registered under the specified name. + */ +struct nl_cache_ops *nl_cache_ops_lookup(const char *name) +{ + struct nl_cache_ops *ops; + + for (ops = cache_ops; ops; ops = ops->co_next) + if (!strcmp(ops->co_name, name)) + return ops; + + return NULL; +} + +/** + * Associate a message type to a set of cache operations + * @arg protocol netlink protocol + * @arg msgtype netlink message type + * + * Associates the specified netlink message type with + * a registered set of cache operations. + * + * @return The cache operations or NULL if no association + * could be made. + */ +struct nl_cache_ops *nl_cache_ops_associate(int protocol, int msgtype) +{ + int i; + struct nl_cache_ops *ops; + + for (ops = cache_ops; ops; ops = ops->co_next) { + if (ops->co_protocol != protocol) + continue; + + for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) + if (ops->co_msgtypes[i].mt_id == msgtype) + return ops; + } + + return NULL; +} + +/** + * Lookup message type cache association + * @arg ops cache operations + * @arg msgtype netlink message type + * + * Searches for a matching message type association ing the specified + * cache operations. + * + * @return A message type association or NULL. + */ +struct nl_msgtype *nl_msgtype_lookup(struct nl_cache_ops *ops, int msgtype) +{ + int i; + + for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) + if (ops->co_msgtypes[i].mt_id == msgtype) + return &ops->co_msgtypes[i]; + + return NULL; +} + +static struct nl_cache_ops *cache_ops_lookup_for_obj(struct nl_object_ops *obj_ops) +{ + struct nl_cache_ops *ops; + + for (ops = cache_ops; ops; ops = ops->co_next) + if (ops->co_obj_ops == obj_ops) + return ops; + + return NULL; + +} + +/** + * Call a function for each registered cache operation + * @arg cb Callback function to be called + * @arg arg User specific argument. + */ +void nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *arg) +{ + struct nl_cache_ops *ops; + + for (ops = cache_ops; ops; ops = ops->co_next) + cb(ops, arg); +} + +/** + * Register a set of cache operations + * @arg ops cache operations + * + * Called by users of caches to announce the avaibility of + * a certain cache type. + * + * @return 0 on success or a negative error code. + */ +int nl_cache_mngt_register(struct nl_cache_ops *ops) +{ + if (!ops->co_name || !ops->co_obj_ops) + return -NLE_INVAL; + + if (nl_cache_ops_lookup(ops->co_name)) + return -NLE_EXIST; + + ops->co_next = cache_ops; + cache_ops = ops; + + NL_DBG(1, "Registered cache operations %s\n", ops->co_name); + + return 0; +} + +/** + * Unregister a set of cache operations + * @arg ops cache operations + * + * Called by users of caches to announce a set of + * cache operations is no longer available. The + * specified cache operations must have been registered + * previously using nl_cache_mngt_register() + * + * @return 0 on success or a negative error code + */ +int nl_cache_mngt_unregister(struct nl_cache_ops *ops) +{ + struct nl_cache_ops *t, **tp; + + for (tp = &cache_ops; (t=*tp) != NULL; tp = &t->co_next) + if (t == ops) + break; + + if (!t) + return -NLE_NOCACHE; + + NL_DBG(1, "Unregistered cache operations %s\n", ops->co_name); + + *tp = t->co_next; + return 0; +} + +/** @} */ + +/** + * @name Global Cache Provisioning/Requiring + * @{ + */ + +/** + * Provide a cache for global use + * @arg cache cache to provide + * + * Offers the specified cache to be used by other modules. + * Only one cache per type may be shared at a time, + * a previsouly provided caches will be overwritten. + */ +void nl_cache_mngt_provide(struct nl_cache *cache) +{ + struct nl_cache_ops *ops; + + ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops); + if (!ops) + BUG(); + else + ops->co_major_cache = cache; +} + +/** + * Unprovide a cache for global use + * @arg cache cache to unprovide + * + * Cancels the offer to use a cache globally. The + * cache will no longer be returned via lookups but + * may still be in use. + */ +void nl_cache_mngt_unprovide(struct nl_cache *cache) +{ + struct nl_cache_ops *ops; + + ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops); + if (!ops) + BUG(); + else if (ops->co_major_cache == cache) + ops->co_major_cache = NULL; +} + +struct nl_cache *__nl_cache_mngt_require(const char *name) +{ + struct nl_cache_ops *ops; + + ops = nl_cache_ops_lookup(name); + if (ops) + return ops->co_major_cache; + + return NULL; +} + +/** + * Demand the use of a global cache + * @arg name name of the required object type + * + * Trys to find a cache of the specified type for global + * use. + * + * @return A cache provided by another subsystem of the + * specified type marked to be available. + */ +struct nl_cache *nl_cache_mngt_require(const char *name) +{ + struct nl_cache *cache; + + if (!(cache = __nl_cache_mngt_require(name))) + fprintf(stderr, "Application BUG: Your application must " + "call nl_cache_mngt_provide() and\nprovide a valid " + "%s cache to be used for internal lookups.\nSee the " + " API documentation for more details.\n", name); + + return cache; +} + +/** @} */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/cli/cls/.dirstamp b/libnetwork/libnl3/lib/cli/cls/.dirstamp new file mode 100644 index 0000000..e69de29 diff --git a/libnetwork/libnl3/lib/cli/cls/basic.c b/libnetwork/libnl3/lib/cli/cls/basic.c new file mode 100644 index 0000000..1939988 --- /dev/null +++ b/libnetwork/libnl3/lib/cli/cls/basic.c @@ -0,0 +1,93 @@ +/* + * lib/cli/cls/basic.c basic classifier module for CLI lib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010-2011 Thomas Graf + */ + +#include +#include +#include +#include + +static void print_usage(void) +{ + printf( +"Usage: nl-cls-add [...] basic [OPTIONS]...\n" +"\n" +"OPTIONS\n" +" -h, --help Show this help text.\n" +" -t, --target=ID Target class to send matching packets to\n" +" -e, --ematch=EXPR Ematch expression\n" +"\n" +"EXAMPLE" +" # Create a \"catch-all\" classifier, attached to \"q_root\", classyfing\n" +" # all not yet classified packets to class \"c_default\"\n" +" nl-cls-add --dev=eth0 --parent=q_root basic --target=c_default\n"); +} + +static void parse_argv(struct rtnl_tc *tc, int argc, char **argv) +{ + struct rtnl_cls *cls = (struct rtnl_cls *) tc; + struct rtnl_ematch_tree *tree; + uint32_t target; + int err; + + for (;;) { + int c, optidx = 0; + enum { + ARG_TARGET = 257, + ARG_DEFAULT = 258, + }; + static struct option long_opts[] = { + { "help", 0, 0, 'h' }, + { "target", 1, 0, 't' }, + { "ematch", 1, 0, 'e' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "ht:e:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'h': + print_usage(); + exit(0); + + case 't': + if ((err = rtnl_tc_str2handle(optarg, &target)) < 0) + nl_cli_fatal(err, "Unable to parse target \"%s\":", + optarg, nl_geterror(err)); + + rtnl_basic_set_target(cls, target); + break; + + case 'e': + tree = nl_cli_cls_parse_ematch(cls, optarg); + rtnl_basic_set_ematch(cls, tree); + break; + } + } +} + +static struct nl_cli_tc_module basic_module = +{ + .tm_name = "basic", + .tm_type = RTNL_TC_TYPE_CLS, + .tm_parse_argv = parse_argv, +}; + +static void __init basic_init(void) +{ + nl_cli_tc_register(&basic_module); +} + +static void __exit basic_exit(void) +{ + nl_cli_tc_unregister(&basic_module); +} diff --git a/libnetwork/libnl3/lib/cli/cls/cgroup.c b/libnetwork/libnl3/lib/cli/cls/cgroup.c new file mode 100644 index 0000000..fae6208 --- /dev/null +++ b/libnetwork/libnl3/lib/cli/cls/cgroup.c @@ -0,0 +1,75 @@ +/* + * lib/cli/cls/cgroup.c cgroup classifier module for CLI lib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010-2011 Thomas Graf + */ + +#include +#include +#include +#include + +static void print_usage(void) +{ + printf( +"Usage: nl-cls-add [...] cgroup [OPTIONS]...\n" +"\n" +"OPTIONS\n" +" -h, --help Show this help text.\n" +" -e, --ematch=EXPR Ematch expression\n" +"\n" +"EXAMPLE" +" nl-cls-add --dev=eth0 --parent=q_root cgroup\n"); +} + +static void parse_argv(struct rtnl_tc *tc, int argc, char **argv) +{ + struct rtnl_cls *cls = (struct rtnl_cls *) tc; + struct rtnl_ematch_tree *tree; + + for (;;) { + int c, optidx = 0; + static struct option long_opts[] = { + { "help", 0, 0, 'h' }, + { "ematch", 1, 0, 'e' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "he:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'h': + print_usage(); + exit(0); + + case 'e': + tree = nl_cli_cls_parse_ematch(cls, optarg); + rtnl_cgroup_set_ematch(cls, tree); + break; + } + } +} + +static struct nl_cli_tc_module cgroup_module = +{ + .tm_name = "cgroup", + .tm_type = RTNL_TC_TYPE_CLS, + .tm_parse_argv = parse_argv, +}; + +static void __init cgroup_init(void) +{ + nl_cli_tc_register(&cgroup_module); +} + +static void __exit cgroup_exit(void) +{ + nl_cli_tc_unregister(&cgroup_module); +} diff --git a/libnetwork/libnl3/lib/cli/qdisc/.dirstamp b/libnetwork/libnl3/lib/cli/qdisc/.dirstamp new file mode 100644 index 0000000..e69de29 diff --git a/libnetwork/libnl3/lib/cli/qdisc/bfifo.c b/libnetwork/libnl3/lib/cli/qdisc/bfifo.c new file mode 100644 index 0000000..1ee4777 --- /dev/null +++ b/libnetwork/libnl3/lib/cli/qdisc/bfifo.c @@ -0,0 +1,83 @@ +/* + * src/lib/bfifo.c bfifo module for CLI lib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010-2011 Thomas Graf + */ + +#include +#include +#include + +static void print_usage(void) +{ + printf( +"Usage: nl-qdisc-add [...] bfifo [OPTIONS]...\n" +"\n" +"OPTIONS\n" +" --help Show this help text.\n" +" --limit=LIMIT Maximum queue length in number of bytes.\n" +"\n" +"EXAMPLE" +" # Attach bfifo with a 4KB bytes limit to eth1\n" +" nl-qdisc-add --dev=eth1 --parent=root bfifo --limit=4096\n"); +} + +static void bfifo_parse_argv(struct rtnl_tc *tc, int argc, char **argv) +{ + struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc; + int limit; + + for (;;) { + int c, optidx = 0; + enum { + ARG_LIMIT = 257, + }; + static struct option long_opts[] = { + { "help", 0, 0, 'h' }, + { "limit", 1, 0, ARG_LIMIT }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "h", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'h': + print_usage(); + return; + + case ARG_LIMIT: + limit = nl_size2int(optarg); + if (limit < 0) { + nl_cli_fatal(limit, "Unable to parse bfifo limit " + "\"%s\": Invalid format.", optarg); + } + + rtnl_qdisc_fifo_set_limit(qdisc, limit); + break; + } + } +} + +static struct nl_cli_tc_module bfifo_module = +{ + .tm_name = "bfifo", + .tm_type = RTNL_TC_TYPE_QDISC, + .tm_parse_argv = bfifo_parse_argv, +}; + +static void __init bfifo_init(void) +{ + nl_cli_tc_register(&bfifo_module); +} + +static void __exit bfifo_exit(void) +{ + nl_cli_tc_unregister(&bfifo_module); +} diff --git a/libnetwork/libnl3/lib/cli/qdisc/blackhole.c b/libnetwork/libnl3/lib/cli/qdisc/blackhole.c new file mode 100644 index 0000000..af9dc6d --- /dev/null +++ b/libnetwork/libnl3/lib/cli/qdisc/blackhole.c @@ -0,0 +1,64 @@ +/* + * src/lib/blackhole.c Blackhole module for CLI lib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010-2011 Thomas Graf + */ + +#include +#include + +static void print_usage(void) +{ + printf( +"Usage: nl-qdisc-add [...] blackhole [OPTIONS]...\n" +"\n" +"OPTIONS\n" +" --help Show this help text.\n" +"\n" +"EXAMPLE" +" # Drop all outgoing packets on eth1\n" +" nl-qdisc-add --dev=eth1 --parent=root blackhole\n"); +} + +static void blackhole_parse_argv(struct rtnl_tc *tc, int argc, char **argv) +{ + for (;;) { + int c, optidx = 0; + static struct option long_opts[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "h", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'h': + print_usage(); + return; + } + } +} + +static struct nl_cli_tc_module blackhole_module = +{ + .tm_name = "blackhole", + .tm_type = RTNL_TC_TYPE_QDISC, + .tm_parse_argv = blackhole_parse_argv, +}; + +static void __init blackhole_init(void) +{ + nl_cli_tc_register(&blackhole_module); +} + +static void __exit blackhole_exit(void) +{ + nl_cli_tc_unregister(&blackhole_module); +} diff --git a/libnetwork/libnl3/lib/cli/qdisc/htb.c b/libnetwork/libnl3/lib/cli/qdisc/htb.c new file mode 100644 index 0000000..1751595 --- /dev/null +++ b/libnetwork/libnl3/lib/cli/qdisc/htb.c @@ -0,0 +1,203 @@ +/* + * src/lib/htb.c HTB module for CLI lib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010-2011 Thomas Graf + */ + +#include +#include +#include + +static void print_qdisc_usage(void) +{ + printf( +"Usage: nl-qdisc-add [...] htb [OPTIONS]...\n" +"\n" +"OPTIONS\n" +" --help Show this help text.\n" +" --r2q=DIV Rate to quantum divisor (default: 10)\n" +" --default=ID Default class for unclassified traffic.\n" +"\n" +"EXAMPLE" +" # Create htb root qdisc 1: and direct unclassified traffic to class 1:10\n" +" nl-qdisc-add --dev=eth1 --parent=root --handle=1: htb --default=10\n"); +} + +static void htb_parse_qdisc_argv(struct rtnl_tc *tc, int argc, char **argv) +{ + struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc; + + for (;;) { + int c, optidx = 0; + enum { + ARG_R2Q = 257, + ARG_DEFAULT = 258, + }; + static struct option long_opts[] = { + { "help", 0, 0, 'h' }, + { "r2q", 1, 0, ARG_R2Q }, + { "default", 1, 0, ARG_DEFAULT }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "hv", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'h': + print_qdisc_usage(); + return; + + case ARG_R2Q: + rtnl_htb_set_rate2quantum(qdisc, nl_cli_parse_u32(optarg)); + break; + + case ARG_DEFAULT: + rtnl_htb_set_defcls(qdisc, nl_cli_parse_u32(optarg)); + break; + } + } +} + +static void print_class_usage(void) +{ + printf( +"Usage: nl-class-add [...] htb [OPTIONS]...\n" +"\n" +"OPTIONS\n" +" --help Show this help text.\n" +" --rate=RATE Rate limit.\n" +" --ceil=RATE Rate limit while borrowing (default: equal to --rate).\n" +" --prio=PRIO Priority, lower is served first (default: 0).\n" +" --quantum=SIZE Amount of bytes to serve at once (default: rate/r2q).\n" +" --burst=SIZE Max charge size of rate burst buffer (default: auto).\n" +" --cburst=SIZE Max charge size of ceil rate burst buffer (default: auto)\n" +"\n" +"EXAMPLE" +" # Attach class 1:1 to htb qdisc 1: and rate limit it to 20mbit\n" +" nl-class-add --dev=eth1 --parent=1: --classid=1:1 htb --rate=20mbit\n"); +} + +static void htb_parse_class_argv(struct rtnl_tc *tc, int argc, char **argv) +{ + struct rtnl_class *class = (struct rtnl_class *) tc; + long rate; + + for (;;) { + int c, optidx = 0; + enum { + ARG_RATE = 257, + ARG_QUANTUM = 258, + ARG_CEIL, + ARG_PRIO, + ARG_BURST, + ARG_CBURST, + }; + static struct option long_opts[] = { + { "help", 0, 0, 'h' }, + { "rate", 1, 0, ARG_RATE }, + { "quantum", 1, 0, ARG_QUANTUM }, + { "ceil", 1, 0, ARG_CEIL }, + { "prio", 1, 0, ARG_PRIO }, + { "burst", 1, 0, ARG_BURST }, + { "cburst", 1, 0, ARG_CBURST }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "h", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'h': + print_class_usage(); + return; + + case ARG_RATE: + rate = nl_size2int(optarg); + if (rate < 0) { + nl_cli_fatal(rate, "Unable to parse htb rate " + "\"%s\": Invalid format.", optarg); + } + + rtnl_htb_set_rate(class, rate); + break; + + case ARG_CEIL: + rate = nl_size2int(optarg); + if (rate < 0) { + nl_cli_fatal(rate, "Unable to parse htb ceil rate " + "\"%s\": Invalid format.", optarg); + } + + rtnl_htb_set_ceil(class, rate); + break; + + case ARG_PRIO: + rtnl_htb_set_prio(class, nl_cli_parse_u32(optarg)); + break; + + case ARG_QUANTUM: + rate = nl_size2int(optarg); + if (rate < 0) { + nl_cli_fatal(rate, "Unable to parse quantum " + "\"%s\": Invalid format.", optarg); + } + + rtnl_htb_set_quantum(class, rate); + break; + + case ARG_BURST: + rate = nl_size2int(optarg); + if (rate < 0) { + nl_cli_fatal(rate, "Unable to parse burst " + "\"%s\": Invalid format.", optarg); + } + + rtnl_htb_set_rbuffer(class, rate); + break; + + case ARG_CBURST: + rate = nl_size2int(optarg); + if (rate < 0) { + nl_cli_fatal(rate, "Unable to parse cburst " + "\"%s\": Invalid format.", optarg); + } + + rtnl_htb_set_cbuffer(class, rate); + break; + } + } +} + +static struct nl_cli_tc_module htb_qdisc_module = +{ + .tm_name = "htb", + .tm_type = RTNL_TC_TYPE_QDISC, + .tm_parse_argv = htb_parse_qdisc_argv, +}; + +static struct nl_cli_tc_module htb_class_module = +{ + .tm_name = "htb", + .tm_type = RTNL_TC_TYPE_CLASS, + .tm_parse_argv = htb_parse_class_argv, +}; + +static void __init htb_init(void) +{ + nl_cli_tc_register(&htb_qdisc_module); + nl_cli_tc_register(&htb_class_module); +} + +static void __exit htb_exit(void) +{ + nl_cli_tc_unregister(&htb_class_module); + nl_cli_tc_unregister(&htb_qdisc_module); +} diff --git a/libnetwork/libnl3/lib/cli/qdisc/pfifo.c b/libnetwork/libnl3/lib/cli/qdisc/pfifo.c new file mode 100644 index 0000000..02c4d22 --- /dev/null +++ b/libnetwork/libnl3/lib/cli/qdisc/pfifo.c @@ -0,0 +1,77 @@ + +/* + * src/lib/pfifo.c pfifo module for CLI lib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010-2011 Thomas Graf + */ + +#include +#include +#include + +static void print_usage(void) +{ + printf( +"Usage: nl-qdisc-add [...] pfifo [OPTIONS]...\n" +"\n" +"OPTIONS\n" +" --help Show this help text.\n" +" --limit=LIMIT Maximum queue length in number of packets.\n" +"\n" +"EXAMPLE" +" # Attach pfifo with a 32 packet limit to eth1\n" +" nl-qdisc-add --dev=eth1 --parent=root pfifo --limit=32\n"); +} + +static void pfifo_parse_argv(struct rtnl_tc *tc, int argc, char **argv) +{ + struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc; + + for (;;) { + int c, optidx = 0; + enum { + ARG_LIMIT = 257, + }; + static struct option long_opts[] = { + { "help", 0, 0, 'h' }, + { "limit", 1, 0, ARG_LIMIT }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "h", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'h': + print_usage(); + return; + + case ARG_LIMIT: + rtnl_qdisc_fifo_set_limit(qdisc, nl_cli_parse_u32(optarg)); + break; + } + } +} + +static struct nl_cli_tc_module pfifo_module = +{ + .tm_name = "pfifo", + .tm_type = RTNL_TC_TYPE_QDISC, + .tm_parse_argv = pfifo_parse_argv, +}; + +static void __init pfifo_init(void) +{ + nl_cli_tc_register(&pfifo_module); +} + +static void __exit pfifo_exit(void) +{ + nl_cli_tc_unregister(&pfifo_module); +} diff --git a/libnetwork/libnl3/lib/data.c b/libnetwork/libnl3/lib/data.c new file mode 100644 index 0000000..03cd9fe --- /dev/null +++ b/libnetwork/libnl3/lib/data.c @@ -0,0 +1,186 @@ +/* + * lib/data.c Abstract Data + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup core + * @defgroup data Abstract Data + * @{ + */ + +#include +#include +#include +#include + +/** + * @name General + * @{ + */ + +/** + * Allocate a new abstract data object. + * @arg buf Data buffer containing the actual data. + * @arg size Size of data buffer. + * + * Allocates a new abstract data and copies the specified data + * buffer into the new handle. + * + * @return Newly allocated data handle or NULL + */ +struct nl_data *nl_data_alloc(void *buf, size_t size) +{ + struct nl_data *data; + + data = calloc(1, sizeof(*data)); + if (!data) + goto errout; + + data->d_data = calloc(1, size); + if (!data->d_data) { + free(data); + goto errout; + } + + data->d_size = size; + + if (buf) + memcpy(data->d_data, buf, size); + + return data; +errout: + return NULL; +} + +/** + * Allocate abstract data object based on netlink attribute. + * @arg nla Netlink attribute of unspecific type. + * + * Allocates a new abstract data and copies the payload of the + * attribute to the abstract data object. + * + * @see nla_data_alloc + * @return Newly allocated data handle or NULL + */ +struct nl_data *nl_data_alloc_attr(struct nlattr *nla) +{ + return nl_data_alloc(nla_data(nla), nla_len(nla)); +} + +/** + * Clone an abstract data object. + * @arg src Abstract data object + * + * @return Cloned object or NULL + */ +struct nl_data *nl_data_clone(struct nl_data *src) +{ + return nl_data_alloc(src->d_data, src->d_size); +} + +/** + * Append data to an abstract data object. + * @arg data Abstract data object. + * @arg buf Data buffer containing the data to be appended. + * @arg size Size of data to be apppended. + * + * Reallocates an abstract data and copies the specified data + * buffer into the new handle. + * + * @return 0 on success or a negative error code + */ +int nl_data_append(struct nl_data *data, void *buf, size_t size) +{ + if (size < 0) + BUG(); + + if (size > 0) { + data->d_data = realloc(data->d_data, data->d_size + size); + if (!data->d_data) + return -NLE_NOMEM; + + if (buf) + memcpy(data->d_data + data->d_size, buf, size); + else + memset(data->d_data + data->d_size, 0, size); + + data->d_size += size; + } + + return 0; +} + +/** + * Free an abstract data object. + * @arg data Abstract data object. + */ +void nl_data_free(struct nl_data *data) +{ + if (data) + free(data->d_data); + + free(data); +} + +/** @} */ + +/** + * @name Attribute Access + * @{ + */ + +/** + * Get data buffer of abstract data object. + * @arg data Abstract data object. + * @return Data buffer or NULL if empty. + */ +void *nl_data_get(struct nl_data *data) +{ + return data->d_size > 0 ? data->d_data : NULL; +} + +/** + * Get size of data buffer of abstract data object. + * @arg data Abstract data object. + * @return Size of data buffer. + */ +size_t nl_data_get_size(struct nl_data *data) +{ + return data->d_size; +} + +/** @} */ + +/** + * @name Misc + * @{ + */ + +/** + * Compare two abstract data objects. + * @arg a Abstract data object. + * @arg b Another abstract data object. + * @return An integer less than, equal to, or greater than zero if + * a is found, respectively, to be less than, to match, or + * be greater than b. + */ +int nl_data_cmp(struct nl_data *a, struct nl_data *b) +{ + void *a_ = nl_data_get(a); + void *b_ = nl_data_get(b); + + if (a_ && b_) + return memcmp(a_, b_, nl_data_get_size(a)); + else + return -1; +} + +/** @} */ +/** @} */ diff --git a/libnetwork/libnl3/lib/defs.h b/libnetwork/libnl3/lib/defs.h new file mode 100644 index 0000000..c3bd632 --- /dev/null +++ b/libnetwork/libnl3/lib/defs.h @@ -0,0 +1,85 @@ +/* lib/defs.h. Generated from defs.h.in by configure. */ +/* lib/defs.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM 1 + +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#define HAVE_LIBPTHREAD 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "libnl" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "http://www.infradead.org/~tgr/libnl/" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libnl" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libnl 3.2.3" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libnl" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "3.2.3" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "3.2.3" + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#define YYTEXT_POINTER 1 + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif diff --git a/libnetwork/libnl3/lib/defs.h.in b/libnetwork/libnl3/lib/defs.h.in new file mode 100644 index 0000000..cc3bf5c --- /dev/null +++ b/libnetwork/libnl3/lib/defs.h.in @@ -0,0 +1,84 @@ +/* lib/defs.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `m' library (-lm). */ +#undef HAVE_LIBM + +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#undef HAVE_LIBPTHREAD + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +#undef NO_MINUS_C_MINUS_O + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif diff --git a/libnetwork/libnl3/lib/error.c b/libnetwork/libnl3/lib/error.c new file mode 100644 index 0000000..e8ee474 --- /dev/null +++ b/libnetwork/libnl3/lib/error.c @@ -0,0 +1,116 @@ +/* + * lib/error.c Error Handling + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Thomas Graf + */ + +#include +#include + +static const char *errmsg[NLE_MAX+1] = { +[NLE_SUCCESS] = "Success", +[NLE_FAILURE] = "Unspecific failure", +[NLE_INTR] = "Interrupted system call", +[NLE_BAD_SOCK] = "Bad socket", +[NLE_AGAIN] = "Try again", +[NLE_NOMEM] = "Out of memory", +[NLE_EXIST] = "Object exists", +[NLE_INVAL] = "Invalid input data or parameter", +[NLE_RANGE] = "Input data out of range", +[NLE_MSGSIZE] = "Message size not sufficient", +[NLE_OPNOTSUPP] = "Operation not supported", +[NLE_AF_NOSUPPORT] = "Address family not supported", +[NLE_OBJ_NOTFOUND] = "Object not found", +[NLE_NOATTR] = "Attribute not available", +[NLE_MISSING_ATTR] = "Missing attribute", +[NLE_AF_MISMATCH] = "Address family mismatch", +[NLE_SEQ_MISMATCH] = "Message sequence number mismatch", +[NLE_MSG_OVERFLOW] = "Kernel reported message overflow", +[NLE_MSG_TRUNC] = "Kernel reported truncated message", +[NLE_NOADDR] = "Invalid address for specified address family", +[NLE_SRCRT_NOSUPPORT] = "Source based routing not supported", +[NLE_MSG_TOOSHORT] = "Netlink message is too short", +[NLE_MSGTYPE_NOSUPPORT] = "Netlink message type is not supported", +[NLE_OBJ_MISMATCH] = "Object type does not match cache", +[NLE_NOCACHE] = "Unknown or invalid cache type", +[NLE_BUSY] = "Object busy", +[NLE_PROTO_MISMATCH] = "Protocol mismatch", +[NLE_NOACCESS] = "No Access", +[NLE_PERM] = "Operation not permitted", +[NLE_PKTLOC_FILE] = "Unable to open packet location file", +[NLE_PARSE_ERR] = "Unable to parse object", +[NLE_NODEV] = "No such device", +[NLE_IMMUTABLE] = "Immutable attribute", +[NLE_DUMP_INTR] = "Dump inconsistency detected, interrupted", +}; + +/** + * Return error message for an error code + * @return error message + */ +const char *nl_geterror(int error) +{ + error = abs(error); + + if (error > NLE_MAX) + error = NLE_FAILURE; + + return errmsg[error]; +} + +/** + * Print a libnl error message + * @arg s error message prefix + * + * Prints the error message of the call that failed last. + * + * If s is not NULL and *s is not a null byte the argument + * string is printed, followed by a colon and a blank. Then + * the error message and a new-line. + */ +void nl_perror(int error, const char *s) +{ + if (s && *s) + fprintf(stderr, "%s: %s\n", s, nl_geterror(error)); + else + fprintf(stderr, "%s\n", nl_geterror(error)); +} + +int nl_syserr2nlerr(int error) +{ + error = abs(error); + + switch (error) { + case EBADF: return NLE_BAD_SOCK; + case EADDRINUSE: return NLE_EXIST; + case EEXIST: return NLE_EXIST; + case EADDRNOTAVAIL: return NLE_NOADDR; + case ESRCH: /* fall through */ + case ENOENT: return NLE_OBJ_NOTFOUND; + case EINTR: return NLE_INTR; + case EAGAIN: return NLE_AGAIN; + case ENOTSOCK: return NLE_BAD_SOCK; + case ENOPROTOOPT: return NLE_INVAL; + case EFAULT: return NLE_INVAL; + case EACCES: return NLE_NOACCESS; + case EINVAL: return NLE_INVAL; + case ENOBUFS: return NLE_NOMEM; + case ENOMEM: return NLE_NOMEM; + case EAFNOSUPPORT: return NLE_AF_NOSUPPORT; + case EPROTONOSUPPORT: return NLE_PROTO_MISMATCH; + case EOPNOTSUPP: return NLE_OPNOTSUPP; + case EPERM: return NLE_PERM; + case EBUSY: return NLE_BUSY; + case ERANGE: return NLE_RANGE; + case ENODEV: return NLE_NODEV; + default: return NLE_FAILURE; + } +} + +/** @} */ + diff --git a/libnetwork/libnl3/lib/fib_lookup/.dirstamp b/libnetwork/libnl3/lib/fib_lookup/.dirstamp new file mode 100644 index 0000000..e69de29 diff --git a/libnetwork/libnl3/lib/fib_lookup/lookup.c b/libnetwork/libnl3/lib/fib_lookup/lookup.c new file mode 100644 index 0000000..6018251 --- /dev/null +++ b/libnetwork/libnl3/lib/fib_lookup/lookup.c @@ -0,0 +1,348 @@ +/* + * lib/fib_lookup/lookup.c FIB Lookup + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @defgroup fib_lookup FIB Lookup + * @brief + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +static struct nl_cache_ops fib_lookup_ops; +static struct nl_object_ops result_obj_ops; + +/* not exported so far */ +struct fib_result_nl { + uint32_t fl_addr; /* To be looked up*/ + uint32_t fl_fwmark; + unsigned char fl_tos; + unsigned char fl_scope; + unsigned char tb_id_in; + + unsigned char tb_id; /* Results */ + unsigned char prefixlen; + unsigned char nh_sel; + unsigned char type; + unsigned char scope; + int err; +}; +/** @endcond */ + +static void result_free_data(struct nl_object *obj) +{ + struct flnl_result *res = nl_object_priv(obj); + + if (res && res->fr_req) + nl_object_put(OBJ_CAST(res->fr_req)); +} + +static int result_clone(struct nl_object *_dst, struct nl_object *_src) +{ + struct flnl_result *dst = nl_object_priv(_dst); + struct flnl_result *src = nl_object_priv(_src); + + if (src->fr_req) + if (!(dst->fr_req = (struct flnl_request *) + nl_object_clone(OBJ_CAST(src->fr_req)))) + return -NLE_NOMEM; + + return 0; +} + +static int result_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *n, struct nl_parser_param *pp) +{ + struct flnl_result *res; + struct fib_result_nl *fr; + struct nl_addr *addr; + int err = -NLE_INVAL; + + res = flnl_result_alloc(); + if (!res) + goto errout; + + res->ce_msgtype = n->nlmsg_type; + + res->fr_req = flnl_request_alloc(); + if (!res->fr_req) + goto errout; + + fr = nlmsg_data(n); + addr = nl_addr_build(AF_INET, &fr->fl_addr, 4); + if (!addr) + goto errout; + err = flnl_request_set_addr(res->fr_req, addr); + nl_addr_put(addr); + if (err < 0) + goto errout; + + flnl_request_set_fwmark(res->fr_req, fr->fl_fwmark); + flnl_request_set_tos(res->fr_req, fr->fl_tos); + flnl_request_set_scope(res->fr_req, fr->fl_scope); + flnl_request_set_table(res->fr_req, fr->tb_id_in); + + res->fr_table_id = fr->tb_id; + res->fr_prefixlen = fr->prefixlen; + res->fr_nh_sel = fr->nh_sel; + res->fr_type = fr->type; + res->fr_scope = fr->scope; + res->fr_error = fr->err; + + err = pp->pp_cb((struct nl_object *) res, pp); + if (err < 0) + goto errout; + + /* REAL HACK, fib_lookup doesn't support ACK nor does it + * send a DONE message, enforce end of message stream + * after just the first message */ + err = NL_STOP; + +errout: + flnl_result_put(res); + return err; +} + +static void result_dump_line(struct nl_object *obj, struct nl_dump_params *p) +{ + struct flnl_result *res = (struct flnl_result *) obj; + char buf[128]; + + nl_dump_line(p, "table %s prefixlen %u next-hop-selector %u\n", + rtnl_route_table2str(res->fr_table_id, buf, sizeof(buf)), + res->fr_prefixlen, res->fr_nh_sel); + nl_dump_line(p, "type %s ", + nl_rtntype2str(res->fr_type, buf, sizeof(buf))); + nl_dump(p, "scope %s error %s (%d)\n", + rtnl_scope2str(res->fr_scope, buf, sizeof(buf)), + strerror(-res->fr_error), res->fr_error); +} + +static void result_dump_details(struct nl_object *obj, struct nl_dump_params *p) +{ + result_dump_line(obj, p); +} + +static int result_compare(struct nl_object *_a, struct nl_object *_b, + uint32_t attrs, int flags) +{ + return 0; +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct flnl_result *flnl_result_alloc(void) +{ + return (struct flnl_result *) nl_object_alloc(&result_obj_ops); +} + +void flnl_result_put(struct flnl_result *res) +{ + nl_object_put((struct nl_object *) res); +} + +/** @} */ + +/** + * @name Cache Management + * @{ + */ + +/** + * Allocate lookup result cache. + * + * Allocates a new lookup result cache and initializes it properly. + * + * @note Free the memory after usage using nl_cache_destroy_and_free(). + * @return Newly allocated cache or NULL if an error occured. + */ +struct nl_cache *flnl_result_alloc_cache(void) +{ + return nl_cache_alloc(&fib_lookup_ops); +} + +/** @} */ + +/** + * @name Lookup + * @{ + */ + +/** + * Builds a netlink request message to do a lookup + * @arg req Requested match. + * @arg flags additional netlink message flags + * @arg result Result pointer + * + * Builds a new netlink message requesting a change of link attributes. + * The netlink message header isn't fully equipped with all relevant + * fields and must be sent out via nl_send_auto_complete() or + * supplemented as needed. + * \a old must point to a link currently configured in the kernel + * and \a tmpl must contain the attributes to be changed set via + * \c rtnl_link_set_* functions. + * + * @return 0 on success or a negative error code. + */ +int flnl_lookup_build_request(struct flnl_request *req, int flags, + struct nl_msg **result) +{ + struct nl_msg *msg; + struct nl_addr *addr; + uint64_t fwmark; + int tos, scope, table; + struct fib_result_nl fr = {0}; + + fwmark = flnl_request_get_fwmark(req); + tos = flnl_request_get_tos(req); + scope = flnl_request_get_scope(req); + table = flnl_request_get_table(req); + + fr.fl_fwmark = fwmark != UINT_LEAST64_MAX ? fwmark : 0; + fr.fl_tos = tos >= 0 ? tos : 0; + fr.fl_scope = scope >= 0 ? scope : RT_SCOPE_UNIVERSE; + fr.tb_id_in = table >= 0 ? table : RT_TABLE_UNSPEC; + + addr = flnl_request_get_addr(req); + if (!addr) + return -NLE_MISSING_ATTR; + + fr.fl_addr = *(uint32_t *) nl_addr_get_binary_addr(addr); + + msg = nlmsg_alloc_simple(0, flags); + if (!msg) + return -NLE_NOMEM; + + if (nlmsg_append(msg, &fr, sizeof(fr), NLMSG_ALIGNTO) < 0) + goto errout; + + *result = msg; + return 0; + +errout: + nlmsg_free(msg); + return -NLE_MSGSIZE; +} + +/** + * Perform FIB Lookup + * @arg sk Netlink socket. + * @arg req Lookup request object. + * @arg cache Cache for result. + * + * Builds a netlink message to request a FIB lookup, waits for the + * reply and adds the result to the specified cache. + * + * @return 0 on success or a negative error code. + */ +int flnl_lookup(struct nl_sock *sk, struct flnl_request *req, + struct nl_cache *cache) +{ + struct nl_msg *msg; + int err; + + if ((err = flnl_lookup_build_request(req, 0, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return nl_cache_pickup(sk, cache); +} + +/** @} */ + +/** + * @name Attribute Access + * @{ + */ + +int flnl_result_get_table_id(struct flnl_result *res) +{ + return res->fr_table_id; +} + +int flnl_result_get_prefixlen(struct flnl_result *res) +{ + return res->fr_prefixlen; +} + +int flnl_result_get_nexthop_sel(struct flnl_result *res) +{ + return res->fr_nh_sel; +} + +int flnl_result_get_type(struct flnl_result *res) +{ + return res->fr_type; +} + +int flnl_result_get_scope(struct flnl_result *res) +{ + return res->fr_scope; +} + +int flnl_result_get_error(struct flnl_result *res) +{ + return res->fr_error; +} + +/** @} */ + +static struct nl_object_ops result_obj_ops = { + .oo_name = "fib_lookup/result", + .oo_size = sizeof(struct flnl_result), + .oo_free_data = result_free_data, + .oo_clone = result_clone, + .oo_dump = { + [NL_DUMP_LINE] = result_dump_line, + [NL_DUMP_DETAILS] = result_dump_details, + }, + .oo_compare = result_compare, +}; + +static struct nl_cache_ops fib_lookup_ops = { + .co_name = "fib_lookup/fib_lookup", + .co_hdrsize = sizeof(struct fib_result_nl), + .co_msgtypes = { + { 0, NL_ACT_UNSPEC, "any" }, + END_OF_MSGTYPES_LIST, + }, + .co_protocol = NETLINK_FIB_LOOKUP, + .co_msg_parser = result_msg_parser, + .co_obj_ops = &result_obj_ops, +}; + +static void __init fib_lookup_init(void) +{ + nl_cache_mngt_register(&fib_lookup_ops); +} + +static void __exit fib_lookup_exit(void) +{ + nl_cache_mngt_unregister(&fib_lookup_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/fib_lookup/request.c b/libnetwork/libnl3/lib/fib_lookup/request.c new file mode 100644 index 0000000..ffcf8f5 --- /dev/null +++ b/libnetwork/libnl3/lib/fib_lookup/request.c @@ -0,0 +1,185 @@ +/* + * lib/fib_lookup/request.c FIB Lookup Request + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup fib_lookup + * @defgroup flreq Request + * @brief + * @{ + */ + +#include +#include +#include +#include +#include +#include + +static struct nl_object_ops request_obj_ops; + +/** @cond SKIP */ +#define REQUEST_ATTR_ADDR 0x01 +#define REQUEST_ATTR_FWMARK 0x02 +#define REQUEST_ATTR_TOS 0x04 +#define REQUEST_ATTR_SCOPE 0x08 +#define REQUEST_ATTR_TABLE 0x10 +/** @endcond */ + +static void request_free_data(struct nl_object *obj) +{ + struct flnl_request *req = REQUEST_CAST(obj); + + if (req) + nl_addr_put(req->lr_addr); +} + +static int request_clone(struct nl_object *_dst, struct nl_object *_src) +{ + struct flnl_request *dst = nl_object_priv(_dst); + struct flnl_request *src = nl_object_priv(_src); + + if (src->lr_addr) + if (!(dst->lr_addr = nl_addr_clone(src->lr_addr))) + return -NLE_NOMEM; + + return 0; +} + +static int request_compare(struct nl_object *_a, struct nl_object *_b, + uint32_t attrs, int flags) +{ + struct flnl_request *a = (struct flnl_request *) _a; + struct flnl_request *b = (struct flnl_request *) _b; + int diff = 0; + +#define REQ_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, REQUEST_ATTR_##ATTR, a, b, EXPR) + + diff |= REQ_DIFF(FWMARK, a->lr_fwmark != b->lr_fwmark); + diff |= REQ_DIFF(TOS, a->lr_tos != b->lr_tos); + diff |= REQ_DIFF(SCOPE, a->lr_scope != b->lr_scope); + diff |= REQ_DIFF(TABLE, a->lr_table != b->lr_table); + diff |= REQ_DIFF(ADDR, nl_addr_cmp(a->lr_addr, b->lr_addr)); + +#undef REQ_DIFF + + return diff; +} + + +/** + * @name Lookup Request Creation/Deletion + * @{ + */ + +struct flnl_request *flnl_request_alloc(void) +{ + return REQUEST_CAST(nl_object_alloc(&request_obj_ops)); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void flnl_request_set_fwmark(struct flnl_request *req, uint64_t fwmark) +{ + req->lr_fwmark = fwmark; + req->ce_mask |= REQUEST_ATTR_FWMARK; +} + +uint64_t flnl_request_get_fwmark(struct flnl_request *req) +{ + if (req->ce_mask & REQUEST_ATTR_FWMARK) + return req->lr_fwmark; + else + return UINT_LEAST64_MAX; +} + +void flnl_request_set_tos(struct flnl_request *req, int tos) +{ + req->lr_tos = tos; + req->ce_mask |= REQUEST_ATTR_TOS; +} + +int flnl_request_get_tos(struct flnl_request *req) +{ + if (req->ce_mask & REQUEST_ATTR_TOS) + return req->lr_tos; + else + return -1; +} + +void flnl_request_set_scope(struct flnl_request *req, int scope) +{ + req->lr_scope = scope; + req->ce_mask |= REQUEST_ATTR_SCOPE; +} + +int flnl_request_get_scope(struct flnl_request *req) +{ + if (req->ce_mask & REQUEST_ATTR_SCOPE) + return req->lr_scope; + else + return -1; +} + +void flnl_request_set_table(struct flnl_request *req, int table) +{ + req->lr_table = table; + req->ce_mask |= REQUEST_ATTR_TABLE; +} + +int flnl_request_get_table(struct flnl_request *req) +{ + if (req->ce_mask & REQUEST_ATTR_TABLE) + return req->lr_table; + else + return -1; +} + +int flnl_request_set_addr(struct flnl_request *req, struct nl_addr *addr) +{ + if (addr->a_family != AF_INET) + return -NLE_AF_NOSUPPORT; + + if (req->lr_addr) + nl_addr_put(req->lr_addr); + + nl_addr_get(addr); + req->lr_addr = addr; + + req->ce_mask |= REQUEST_ATTR_ADDR; + + return 0; +} + +struct nl_addr *flnl_request_get_addr(struct flnl_request *req) +{ + if (req->ce_mask & REQUEST_ATTR_ADDR) + return req->lr_addr; + else + return NULL; +} + +/** @} */ + +static struct nl_object_ops request_obj_ops = { + .oo_name = "fib_lookup/request", + .oo_size = sizeof(struct flnl_request), + .oo_free_data = request_free_data, + .oo_clone = request_clone, + .oo_compare = request_compare, + .oo_id_attrs = ~0, +}; + +/** @} */ diff --git a/libnetwork/libnl3/lib/genl/.dirstamp b/libnetwork/libnl3/lib/genl/.dirstamp new file mode 100644 index 0000000..e69de29 diff --git a/libnetwork/libnl3/lib/genl/ctrl.c b/libnetwork/libnl3/lib/genl/ctrl.c new file mode 100644 index 0000000..107a4fa --- /dev/null +++ b/libnetwork/libnl3/lib/genl/ctrl.c @@ -0,0 +1,380 @@ +/* + * lib/genl/ctrl.c Generic Netlink Controller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup genl_mngt + * @defgroup ctrl Controller + * @brief + * + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define CTRL_VERSION 0x0001 + +static struct nl_cache_ops genl_ctrl_ops; +/** @endcond */ + +static int ctrl_request_update(struct nl_cache *c, struct nl_sock *h) +{ + return genl_send_simple(h, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, + CTRL_VERSION, NLM_F_DUMP); +} + +static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = { + [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, + [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING, + .maxlen = GENL_NAMSIZ }, + [CTRL_ATTR_VERSION] = { .type = NLA_U32 }, + [CTRL_ATTR_HDRSIZE] = { .type = NLA_U32 }, + [CTRL_ATTR_MAXATTR] = { .type = NLA_U32 }, + [CTRL_ATTR_OPS] = { .type = NLA_NESTED }, + [CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED }, +}; + +static struct nla_policy family_op_policy[CTRL_ATTR_OP_MAX+1] = { + [CTRL_ATTR_OP_ID] = { .type = NLA_U32 }, + [CTRL_ATTR_OP_FLAGS] = { .type = NLA_U32 }, +}; + +static struct nla_policy family_grp_policy[CTRL_ATTR_MCAST_GRP_MAX+1] = { + [CTRL_ATTR_MCAST_GRP_NAME] = { .type = NLA_STRING }, + [CTRL_ATTR_MCAST_GRP_ID] = { .type = NLA_U32 }, +}; + +static int ctrl_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd, + struct genl_info *info, void *arg) +{ + struct genl_family *family; + struct nl_parser_param *pp = arg; + int err; + + family = genl_family_alloc(); + if (family == NULL) { + err = -NLE_NOMEM; + goto errout; + } + + if (info->attrs[CTRL_ATTR_FAMILY_NAME] == NULL) { + err = -NLE_MISSING_ATTR; + goto errout; + } + + if (info->attrs[CTRL_ATTR_FAMILY_ID] == NULL) { + err = -NLE_MISSING_ATTR; + goto errout; + } + + family->ce_msgtype = info->nlh->nlmsg_type; + genl_family_set_id(family, + nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID])); + genl_family_set_name(family, + nla_get_string(info->attrs[CTRL_ATTR_FAMILY_NAME])); + + if (info->attrs[CTRL_ATTR_VERSION]) { + uint32_t version = nla_get_u32(info->attrs[CTRL_ATTR_VERSION]); + genl_family_set_version(family, version); + } + + if (info->attrs[CTRL_ATTR_HDRSIZE]) { + uint32_t hdrsize = nla_get_u32(info->attrs[CTRL_ATTR_HDRSIZE]); + genl_family_set_hdrsize(family, hdrsize); + } + + if (info->attrs[CTRL_ATTR_MAXATTR]) { + uint32_t maxattr = nla_get_u32(info->attrs[CTRL_ATTR_MAXATTR]); + genl_family_set_maxattr(family, maxattr); + } + + if (info->attrs[CTRL_ATTR_OPS]) { + struct nlattr *nla, *nla_ops; + int remaining; + + nla_ops = info->attrs[CTRL_ATTR_OPS]; + nla_for_each_nested(nla, nla_ops, remaining) { + struct nlattr *tb[CTRL_ATTR_OP_MAX+1]; + int flags = 0, id; + + err = nla_parse_nested(tb, CTRL_ATTR_OP_MAX, nla, + family_op_policy); + if (err < 0) + goto errout; + + if (tb[CTRL_ATTR_OP_ID] == NULL) { + err = -NLE_MISSING_ATTR; + goto errout; + } + + id = nla_get_u32(tb[CTRL_ATTR_OP_ID]); + + if (tb[CTRL_ATTR_OP_FLAGS]) + flags = nla_get_u32(tb[CTRL_ATTR_OP_FLAGS]); + + err = genl_family_add_op(family, id, flags); + if (err < 0) + goto errout; + + } + } + + if (info->attrs[CTRL_ATTR_MCAST_GROUPS]) { + struct nlattr *nla, *nla_grps; + int remaining; + + nla_grps = info->attrs[CTRL_ATTR_MCAST_GROUPS]; + nla_for_each_nested(nla, nla_grps, remaining) { + struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX+1]; + int id; + const char * name; + + err = nla_parse_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, nla, + family_grp_policy); + if (err < 0) + goto errout; + + if (tb[CTRL_ATTR_MCAST_GRP_ID] == NULL) { + err = -NLE_MISSING_ATTR; + goto errout; + } + id = nla_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]); + + if (tb[CTRL_ATTR_MCAST_GRP_NAME] == NULL) { + err = -NLE_MISSING_ATTR; + goto errout; + } + name = nla_get_string(tb[CTRL_ATTR_MCAST_GRP_NAME]); + + err = genl_family_add_grp(family, id, name); + if (err < 0) + goto errout; + } + + } + + err = pp->pp_cb((struct nl_object *) family, pp); +errout: + genl_family_put(family); + return err; +} + +/** + * @name Cache Management + * @{ + */ + +int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result) +{ + return nl_cache_alloc_and_fill(&genl_ctrl_ops, sock, result); +} + +/** + * Look up generic netlink family by id in the provided cache. + * @arg cache Generic netlink family cache. + * @arg id Family identifier. + * + * Searches through the cache looking for a registered family + * matching the specified identifier. The caller will own a + * reference on the returned object which needs to be given + * back after usage using genl_family_put(). + * + * @return Generic netlink family object or NULL if no match was found. + */ +struct genl_family *genl_ctrl_search(struct nl_cache *cache, int id) +{ + struct genl_family *fam; + + if (cache->c_ops != &genl_ctrl_ops) + BUG(); + + nl_list_for_each_entry(fam, &cache->c_items, ce_list) { + if (fam->gf_id == id) { + nl_object_get((struct nl_object *) fam); + return fam; + } + } + + return NULL; +} + +/** + * @name Resolver + * @{ + */ + +/** + * Look up generic netlink family by family name in the provided cache. + * @arg cache Generic netlink family cache. + * @arg name Family name. + * + * Searches through the cache looking for a registered family + * matching the specified name. The caller will own a reference + * on the returned object which needs to be given back after + * usage using genl_family_put(). + * + * @return Generic netlink family object or NULL if no match was found. + */ +struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache, + const char *name) +{ + struct genl_family *fam; + + if (cache->c_ops != &genl_ctrl_ops) + BUG(); + + nl_list_for_each_entry(fam, &cache->c_items, ce_list) { + if (!strcmp(name, fam->gf_name)) { + nl_object_get((struct nl_object *) fam); + return fam; + } + } + + return NULL; +} + +/** @} */ + +/** + * Resolve generic netlink family name to its identifier + * @arg sk Netlink socket. + * @arg name Name of generic netlink family + * + * Resolves the generic netlink family name to its identifer and returns + * it. + * + * @return A positive identifier or a negative error code. + */ +int genl_ctrl_resolve(struct nl_sock *sk, const char *name) +{ + struct nl_cache *cache; + struct genl_family *family; + int err; + + if ((err = genl_ctrl_alloc_cache(sk, &cache)) < 0) + return err; + + family = genl_ctrl_search_by_name(cache, name); + if (family == NULL) { + err = -NLE_OBJ_NOTFOUND; + goto errout; + } + + err = genl_family_get_id(family); + genl_family_put(family); +errout: + nl_cache_free(cache); + + return err; +} + +static int genl_ctrl_grp_by_name(const struct genl_family *family, + const char *grp_name) +{ + struct genl_family_grp *grp; + + nl_list_for_each_entry(grp, &family->gf_mc_grps, list) { + if (!strcmp(grp->name, grp_name)) { + return grp->id; + } + } + + return -NLE_OBJ_NOTFOUND; +} + +int genl_ctrl_resolve_grp(struct nl_sock *sk, const char *family_name, + const char *grp_name) +{ + struct nl_cache *cache; + struct genl_family *family; + int err; + + if ((err = genl_ctrl_alloc_cache(sk, &cache)) < 0) + return err; + + family = genl_ctrl_search_by_name(cache, family_name); + if (family == NULL) { + err = -NLE_OBJ_NOTFOUND; + goto errout; + } + + err = genl_ctrl_grp_by_name(family, grp_name); + genl_family_put(family); +errout: + nl_cache_free(cache); + + return err; +} + +/** @} */ + +static struct genl_cmd genl_cmds[] = { + { + .c_id = CTRL_CMD_NEWFAMILY, + .c_name = "NEWFAMILY" , + .c_maxattr = CTRL_ATTR_MAX, + .c_attr_policy = ctrl_policy, + .c_msg_parser = ctrl_msg_parser, + }, + { + .c_id = CTRL_CMD_DELFAMILY, + .c_name = "DELFAMILY" , + }, + { + .c_id = CTRL_CMD_GETFAMILY, + .c_name = "GETFAMILY" , + }, + { + .c_id = CTRL_CMD_NEWOPS, + .c_name = "NEWOPS" , + }, + { + .c_id = CTRL_CMD_DELOPS, + .c_name = "DELOPS" , + }, +}; + +static struct genl_ops genl_ops = { + .o_cmds = genl_cmds, + .o_ncmds = ARRAY_SIZE(genl_cmds), +}; + +/** @cond SKIP */ +extern struct nl_object_ops genl_family_ops; +/** @endcond */ + +static struct nl_cache_ops genl_ctrl_ops = { + .co_name = "genl/family", + .co_hdrsize = GENL_HDRSIZE(0), + .co_msgtypes = GENL_FAMILY(GENL_ID_CTRL, "nlctrl"), + .co_genl = &genl_ops, + .co_protocol = NETLINK_GENERIC, + .co_request_update = ctrl_request_update, + .co_obj_ops = &genl_family_ops, +}; + +static void __init ctrl_init(void) +{ + genl_register(&genl_ctrl_ops); +} + +static void __exit ctrl_exit(void) +{ + genl_unregister(&genl_ctrl_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/genl/family.c b/libnetwork/libnl3/lib/genl/family.c new file mode 100644 index 0000000..ebeebcb --- /dev/null +++ b/libnetwork/libnl3/lib/genl/family.c @@ -0,0 +1,316 @@ +/* + * lib/genl/family.c Generic Netlink Family + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +/** + * @ingroup genl + * @defgroup genl_family Generic Netlink Family + * @brief + * + * @{ + */ + +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define FAMILY_ATTR_ID 0x01 +#define FAMILY_ATTR_NAME 0x02 +#define FAMILY_ATTR_VERSION 0x04 +#define FAMILY_ATTR_HDRSIZE 0x08 +#define FAMILY_ATTR_MAXATTR 0x10 +#define FAMILY_ATTR_OPS 0x20 + +struct nl_object_ops genl_family_ops; +/** @endcond */ + +static void family_constructor(struct nl_object *c) +{ + struct genl_family *family = (struct genl_family *) c; + + nl_init_list_head(&family->gf_ops); + nl_init_list_head(&family->gf_mc_grps); +} + +static void family_free_data(struct nl_object *c) +{ + struct genl_family *family = (struct genl_family *) c; + struct genl_family_op *ops, *tmp; + struct genl_family_grp *grp, *t_grp; + + if (family == NULL) + return; + + nl_list_for_each_entry_safe(ops, tmp, &family->gf_ops, o_list) { + nl_list_del(&ops->o_list); + free(ops); + } + + nl_list_for_each_entry_safe(grp, t_grp, &family->gf_mc_grps, list) { + nl_list_del(&grp->list); + free(grp); + } + +} + +static int family_clone(struct nl_object *_dst, struct nl_object *_src) +{ + struct genl_family *dst = nl_object_priv(_dst); + struct genl_family *src = nl_object_priv(_src); + struct genl_family_op *ops; + struct genl_family_grp *grp; + int err; + + nl_list_for_each_entry(ops, &src->gf_ops, o_list) { + err = genl_family_add_op(dst, ops->o_id, ops->o_flags); + if (err < 0) + return err; + } + + nl_list_for_each_entry(grp, &src->gf_mc_grps, list) { + err = genl_family_add_grp(dst, grp->id, grp->name); + if (err < 0) + return err; + } + + + return 0; +} + +static void family_dump_line(struct nl_object *obj, struct nl_dump_params *p) +{ + struct genl_family *family = (struct genl_family *) obj; + + nl_dump(p, "0x%04x %s version %u\n", + family->gf_id, family->gf_name, family->gf_version); +} + +static const struct trans_tbl ops_flags[] = { + __ADD(GENL_ADMIN_PERM, admin-perm) + __ADD(GENL_CMD_CAP_DO, has-doit) + __ADD(GENL_CMD_CAP_DUMP, has-dump) + __ADD(GENL_CMD_CAP_HASPOL, has-policy) +}; + +static char *ops_flags2str(int flags, char *buf, size_t len) +{ + return __flags2str(flags, buf, len, ops_flags, ARRAY_SIZE(ops_flags)); +} + +static void family_dump_details(struct nl_object *obj, struct nl_dump_params *p) +{ + struct genl_family_grp *grp; + struct genl_family *family = (struct genl_family *) obj; + + family_dump_line(obj, p); + nl_dump_line(p, " hdrsize %u maxattr %u\n", + family->gf_hdrsize, family->gf_maxattr); + + if (family->ce_mask & FAMILY_ATTR_OPS) { + struct genl_family_op *op; + char buf[64]; + + nl_list_for_each_entry(op, &family->gf_ops, o_list) { + ops_flags2str(op->o_flags, buf, sizeof(buf)); + + genl_op2name(family->gf_id, op->o_id, buf, sizeof(buf)); + + nl_dump_line(p, " op %s (0x%02x)", buf, op->o_id); + + if (op->o_flags) + nl_dump(p, " <%s>", + ops_flags2str(op->o_flags, buf, + sizeof(buf))); + + nl_dump(p, "\n"); + } + } + + nl_list_for_each_entry(grp, &family->gf_mc_grps, list) { + nl_dump_line(p, " grp %s (0x%02x)\n", grp->name, grp->id); + } + +} + +static void family_dump_stats(struct nl_object *obj, struct nl_dump_params *p) +{ + family_dump_details(obj, p); +} + +static int family_compare(struct nl_object *_a, struct nl_object *_b, + uint32_t attrs, int flags) +{ + struct genl_family *a = (struct genl_family *) _a; + struct genl_family *b = (struct genl_family *) _b; + int diff = 0; + +#define FAM_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, FAMILY_ATTR_##ATTR, a, b, EXPR) + + diff |= FAM_DIFF(ID, a->gf_id != b->gf_id); + diff |= FAM_DIFF(VERSION, a->gf_version != b->gf_version); + diff |= FAM_DIFF(HDRSIZE, a->gf_hdrsize != b->gf_hdrsize); + diff |= FAM_DIFF(MAXATTR, a->gf_maxattr != b->gf_maxattr); + diff |= FAM_DIFF(NAME, strcmp(a->gf_name, b->gf_name)); + +#undef FAM_DIFF + + return diff; +} + + +/** + * @name Family Object + * @{ + */ + +struct genl_family *genl_family_alloc(void) +{ + return (struct genl_family *) nl_object_alloc(&genl_family_ops); +} + +void genl_family_put(struct genl_family *family) +{ + nl_object_put((struct nl_object *) family); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +unsigned int genl_family_get_id(struct genl_family *family) +{ + if (family->ce_mask & FAMILY_ATTR_ID) + return family->gf_id; + else + return GENL_ID_GENERATE; +} + +void genl_family_set_id(struct genl_family *family, unsigned int id) +{ + family->gf_id = id; + family->ce_mask |= FAMILY_ATTR_ID; +} + +char *genl_family_get_name(struct genl_family *family) +{ + if (family->ce_mask & FAMILY_ATTR_NAME) + return family->gf_name; + else + return NULL; +} + +void genl_family_set_name(struct genl_family *family, const char *name) +{ + strncpy(family->gf_name, name, GENL_NAMSIZ-1); + family->ce_mask |= FAMILY_ATTR_NAME; +} + +uint8_t genl_family_get_version(struct genl_family *family) +{ + if (family->ce_mask & FAMILY_ATTR_VERSION) + return family->gf_version; + else + return 0; +} + +void genl_family_set_version(struct genl_family *family, uint8_t version) +{ + family->gf_version = version; + family->ce_mask |= FAMILY_ATTR_VERSION; +} + +uint32_t genl_family_get_hdrsize(struct genl_family *family) +{ + if (family->ce_mask & FAMILY_ATTR_HDRSIZE) + return family->gf_hdrsize; + else + return 0; +} + +void genl_family_set_hdrsize(struct genl_family *family, uint32_t hdrsize) +{ + family->gf_hdrsize = hdrsize; + family->ce_mask |= FAMILY_ATTR_HDRSIZE; +} + +uint32_t genl_family_get_maxattr(struct genl_family *family) +{ + if (family->ce_mask & FAMILY_ATTR_MAXATTR) + return family->gf_maxattr; + else + return family->gf_maxattr; +} + +void genl_family_set_maxattr(struct genl_family *family, uint32_t maxattr) +{ + family->gf_maxattr = maxattr; + family->ce_mask |= FAMILY_ATTR_MAXATTR; +} + +int genl_family_add_op(struct genl_family *family, int id, int flags) +{ + struct genl_family_op *op; + + op = calloc(1, sizeof(*op)); + if (op == NULL) + return -NLE_NOMEM; + + op->o_id = id; + op->o_flags = flags; + + nl_list_add_tail(&op->o_list, &family->gf_ops); + family->ce_mask |= FAMILY_ATTR_OPS; + + return 0; +} + +int genl_family_add_grp(struct genl_family *family, uint32_t id, + const char *name) +{ + struct genl_family_grp *grp; + + grp = calloc(1, sizeof(*grp)); + if (grp == NULL) + return -NLE_NOMEM; + + grp->id = id; + strncpy(grp->name, name, GENL_NAMSIZ - 1); + + nl_list_add_tail(&grp->list, &family->gf_mc_grps); + + return 0; +} + +/** @} */ + +/** @cond SKIP */ +struct nl_object_ops genl_family_ops = { + .oo_name = "genl/family", + .oo_size = sizeof(struct genl_family), + .oo_constructor = family_constructor, + .oo_free_data = family_free_data, + .oo_clone = family_clone, + .oo_dump = { + [NL_DUMP_LINE] = family_dump_line, + [NL_DUMP_DETAILS] = family_dump_details, + [NL_DUMP_STATS] = family_dump_stats, + }, + .oo_compare = family_compare, + .oo_id_attrs = FAMILY_ATTR_ID, +}; +/** @endcond */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/genl/genl.c b/libnetwork/libnl3/lib/genl/genl.c new file mode 100644 index 0000000..055be91 --- /dev/null +++ b/libnetwork/libnl3/lib/genl/genl.c @@ -0,0 +1,268 @@ +/* + * lib/genl/genl.c Generic Netlink + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @defgroup genl Generic Netlink + * + * @par Message Format + * @code + * <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) ---> + * +----------------------------+- - -+- - - - - - - - - - -+- - -+ + * | Header | Pad | Payload | Pad | + * | struct nlmsghdr | | | | + * +----------------------------+- - -+- - - - - - - - - - -+- - -+ + * @endcode + * @code + * <-------- GENL_HDRLEN -------> <--- hdrlen --> + * <------- genlmsg_len(ghdr) ------> + * +------------------------+- - -+---------------+- - -+------------+ + * | Generic Netlink Header | Pad | Family Header | Pad | Attributes | + * | struct genlmsghdr | | | | | + * +------------------------+- - -+---------------+- - -+------------+ + * genlmsg_data(ghdr)--------------^ ^ + * genlmsg_attrdata(ghdr, hdrlen)------------------------- + * @endcode + * + * @par Example + * @code + * #include + * #include + * #include + * + * struct nl_sock *sock; + * struct nl_msg *msg; + * int family; + * + * // Allocate a new netlink socket + * sock = nl_socket_alloc(); + * + * // Connect to generic netlink socket on kernel side + * genl_connect(sock); + * + * // Ask kernel to resolve family name to family id + * family = genl_ctrl_resolve(sock, "generic_netlink_family_name"); + * + * // Construct a generic netlink by allocating a new message, fill in + * // the header and append a simple integer attribute. + * msg = nlmsg_alloc(); + * genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_ECHO, + * CMD_FOO_GET, FOO_VERSION); + * nla_put_u32(msg, ATTR_FOO, 123); + * + * // Send message over netlink socket + * nl_send_auto_complete(sock, msg); + * + * // Free message + * nlmsg_free(msg); + * + * // Prepare socket to receive the answer by specifying the callback + * // function to be called for valid messages. + * nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, parse_cb, NULL); + * + * // Wait for the answer and receive it + * nl_recvmsgs_default(sock); + * + * static int parse_cb(struct nl_msg *msg, void *arg) + * { + * struct nlmsghdr *nlh = nlmsg_hdr(msg); + * struct nlattr *attrs[ATTR_MAX+1]; + * + * // Validate message and parse attributes + * genlmsg_parse(nlh, 0, attrs, ATTR_MAX, policy); + * + * if (attrs[ATTR_FOO]) { + * uint32_t value = nla_get_u32(attrs[ATTR_FOO]); + * ... + * } + * + * return 0; + * } + * @endcode + * @{ + */ + +#include +#include +#include +#include + +/** + * @name Socket Creating + * @{ + */ + +int genl_connect(struct nl_sock *sk) +{ + return nl_connect(sk, NETLINK_GENERIC); +} + +/** @} */ + +/** + * @name Sending + * @{ + */ + +/** + * Send trivial generic netlink message + * @arg sk Netlink socket. + * @arg family Generic netlink family + * @arg cmd Command + * @arg version Version + * @arg flags Additional netlink message flags. + * + * Fills out a routing netlink request message and sends it out + * using nl_send_simple(). + * + * @return 0 on success or a negative error code. + */ +int genl_send_simple(struct nl_sock *sk, int family, int cmd, + int version, int flags) +{ + struct genlmsghdr hdr = { + .cmd = cmd, + .version = version, + }; + + return nl_send_simple(sk, family, flags, &hdr, sizeof(hdr)); +} + +/** @} */ + + +/** + * @name Message Parsing + * @{ + */ + +int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen) +{ + struct genlmsghdr *ghdr; + + if (!nlmsg_valid_hdr(nlh, GENL_HDRLEN)) + return 0; + + ghdr = nlmsg_data(nlh); + if (genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen)) + return 0; + + return 1; +} + +int genlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype, + struct nla_policy *policy) +{ + struct genlmsghdr *ghdr; + + if (!genlmsg_valid_hdr(nlh, hdrlen)) + return -NLE_MSG_TOOSHORT; + + ghdr = nlmsg_data(nlh); + return nla_validate(genlmsg_attrdata(ghdr, hdrlen), + genlmsg_attrlen(ghdr, hdrlen), maxtype, policy); +} + +int genlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], + int maxtype, struct nla_policy *policy) +{ + struct genlmsghdr *ghdr; + + if (!genlmsg_valid_hdr(nlh, hdrlen)) + return -NLE_MSG_TOOSHORT; + + ghdr = nlmsg_data(nlh); + return nla_parse(tb, maxtype, genlmsg_attrdata(ghdr, hdrlen), + genlmsg_attrlen(ghdr, hdrlen), policy); +} + +/** + * Get head of message payload + * @arg gnlh genetlink messsage header + */ +void *genlmsg_data(const struct genlmsghdr *gnlh) +{ + return ((unsigned char *) gnlh + GENL_HDRLEN); +} + +/** + * Get lenght of message payload + * @arg gnlh genetlink message header + */ +int genlmsg_len(const struct genlmsghdr *gnlh) +{ + struct nlmsghdr *nlh = (struct nlmsghdr *)((unsigned char *)gnlh - + NLMSG_HDRLEN); + return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN); +} + +/** + * Get head of attribute data + * @arg gnlh generic netlink message header + * @arg hdrlen length of family specific header + */ +struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen) +{ + return genlmsg_data(gnlh) + NLMSG_ALIGN(hdrlen); +} + +/** + * Get length of attribute data + * @arg gnlh generic netlink message header + * @arg hdrlen length of family specific header + */ +int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen) +{ + return genlmsg_len(gnlh) - NLMSG_ALIGN(hdrlen); +} + +/** @} */ + +/** + * @name Message Building + * @{ + */ + +/** + * Add generic netlink header to netlink message + * @arg msg netlink message + * @arg pid netlink process id or NL_AUTO_PID + * @arg seq sequence number of message or NL_AUTO_SEQ + * @arg family generic netlink family + * @arg hdrlen length of user specific header + * @arg flags message flags + * @arg cmd generic netlink command + * @arg version protocol version + * + * Returns pointer to user specific header. + */ +void *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family, + int hdrlen, int flags, uint8_t cmd, uint8_t version) +{ + struct nlmsghdr *nlh; + struct genlmsghdr hdr = { + .cmd = cmd, + .version = version, + }; + + nlh = nlmsg_put(msg, pid, seq, family, GENL_HDRLEN + hdrlen, flags); + if (nlh == NULL) + return NULL; + + memcpy(nlmsg_data(nlh), &hdr, sizeof(hdr)); + NL_DBG(2, "msg %p: Added generic netlink header cmd=%d version=%d\n", + msg, cmd, version); + + return nlmsg_data(nlh) + GENL_HDRLEN; +} + +/** @} */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/genl/mngt.c b/libnetwork/libnl3/lib/genl/mngt.c new file mode 100644 index 0000000..0ebe74d --- /dev/null +++ b/libnetwork/libnl3/lib/genl/mngt.c @@ -0,0 +1,273 @@ +/* + * lib/genl/mngt.c Generic Netlink Management + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup genl + * @defgroup genl_mngt Management + * + * @par 1) Registering a generic netlink module + * @code + * #include + * + * // First step is to define all the commands being used in + * // particular generic netlink family. The ID and name are + * // mandatory to be filled out. A callback function and + * // most the attribute policy that comes with it must be + * // defined for commands expected to be issued towards + * // userspace. + * static struct genl_cmd foo_cmds[] = { + * { + * .c_id = FOO_CMD_NEW, + * .c_name = "NEWFOO" , + * .c_maxattr = FOO_ATTR_MAX, + * .c_attr_policy = foo_policy, + * .c_msg_parser = foo_msg_parser, + * }, + * { + * .c_id = FOO_CMD_DEL, + * .c_name = "DELFOO" , + * }, + * }; + * + * // The list of commands must then be integrated into a + * // struct genl_ops serving as handle for this particular + * // family. + * static struct genl_ops my_genl_ops = { + * .o_cmds = foo_cmds, + * .o_ncmds = ARRAY_SIZE(foo_cmds), + * }; + * + * // Using the above struct genl_ops an arbitary number of + * // cache handles can be associated to it. + * // + * // The macro GENL_HDRSIZE() must be used to specify the + * // length of the header to automatically take headers on + * // generic layers into account. + * // + * // The macro GENL_FAMILY() is used to represent the generic + * // netlink family id. + * static struct nl_cache_ops genl_foo_ops = { + * .co_name = "genl/foo", + * .co_hdrsize = GENL_HDRSIZE(sizeof(struct my_hdr)), + * .co_msgtypes = GENL_FAMILY(GENL_ID_GENERATE, "foo"), + * .co_genl = &my_genl_ops, + * .co_protocol = NETLINK_GENERIC, + * .co_request_update = foo_request_update, + * .co_obj_ops = &genl_foo_ops, + * }; + * + * // Finally each cache handle for a generic netlink family + * // must be registered using genl_register(). + * static void __init foo_init(void) + * { + * genl_register(&genl_foo_ops); + * } + * + * // ... respectively unregsted again. + * static void __exit foo_exit(void) + * { + * genl_unregister(&genl_foo_ops); + * } + * @endcode + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include + +static NL_LIST_HEAD(genl_ops_list); + +static int genl_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *nlh, struct nl_parser_param *pp) +{ + int i, err; + struct genlmsghdr *ghdr; + struct genl_cmd *cmd; + + ghdr = nlmsg_data(nlh); + + if (ops->co_genl == NULL) + BUG(); + + for (i = 0; i < ops->co_genl->o_ncmds; i++) { + cmd = &ops->co_genl->o_cmds[i]; + if (cmd->c_id == ghdr->cmd) + goto found; + } + + err = -NLE_MSGTYPE_NOSUPPORT; + goto errout; + +found: + if (cmd->c_msg_parser == NULL) + err = -NLE_OPNOTSUPP; + else { + struct nlattr *tb[cmd->c_maxattr + 1]; + struct genl_info info = { + .who = who, + .nlh = nlh, + .genlhdr = ghdr, + .userhdr = genlmsg_data(ghdr), + .attrs = tb, + }; + + err = nlmsg_parse(nlh, ops->co_hdrsize, tb, cmd->c_maxattr, + cmd->c_attr_policy); + if (err < 0) + goto errout; + + err = cmd->c_msg_parser(ops, cmd, &info, pp); + } +errout: + return err; + +} + +char *genl_op2name(int family, int op, char *buf, size_t len) +{ + struct genl_ops *ops; + int i; + + nl_list_for_each_entry(ops, &genl_ops_list, o_list) { + if (ops->o_family == family) { + for (i = 0; i < ops->o_ncmds; i++) { + struct genl_cmd *cmd; + cmd = &ops->o_cmds[i]; + + if (cmd->c_id == op) { + strncpy(buf, cmd->c_name, len - 1); + return buf; + } + } + } + } + + strncpy(buf, "unknown", len - 1); + return NULL; +} + + +/** + * @name Register/Unregister + * @{ + */ + +/** + * Register generic netlink operations + * @arg ops cache operations + */ +int genl_register(struct nl_cache_ops *ops) +{ + int err; + + if (ops->co_protocol != NETLINK_GENERIC) { + err = -NLE_PROTO_MISMATCH; + goto errout; + } + + if (ops->co_hdrsize < GENL_HDRSIZE(0)) { + err = -NLE_INVAL; + goto errout; + } + + if (ops->co_genl == NULL) { + err = -NLE_INVAL; + goto errout; + } + + ops->co_genl->o_cache_ops = ops; + ops->co_genl->o_name = ops->co_msgtypes[0].mt_name; + ops->co_genl->o_family = ops->co_msgtypes[0].mt_id; + ops->co_msg_parser = genl_msg_parser; + + /* FIXME: check for dup */ + + nl_list_add_tail(&ops->co_genl->o_list, &genl_ops_list); + + err = nl_cache_mngt_register(ops); +errout: + return err; +} + +/** + * Unregister generic netlink operations + * @arg ops cache operations + */ +void genl_unregister(struct nl_cache_ops *ops) +{ + nl_cache_mngt_unregister(ops); + nl_list_del(&ops->co_genl->o_list); +} + +/** @} */ + +/** + * @name Resolving ID/Name + * @{ + */ + +static int __genl_ops_resolve(struct nl_cache *ctrl, struct genl_ops *ops) +{ + struct genl_family *family; + + family = genl_ctrl_search_by_name(ctrl, ops->o_name); + if (family != NULL) { + ops->o_id = genl_family_get_id(family); + genl_family_put(family); + + return 0; + } + + return -NLE_OBJ_NOTFOUND; +} + +int genl_ops_resolve(struct nl_sock *sk, struct genl_ops *ops) +{ + struct nl_cache *ctrl; + int err; + + if ((err = genl_ctrl_alloc_cache(sk, &ctrl)) < 0) + goto errout; + + err = __genl_ops_resolve(ctrl, ops); + + nl_cache_free(ctrl); +errout: + return err; +} + +int genl_mngt_resolve(struct nl_sock *sk) +{ + struct nl_cache *ctrl; + struct genl_ops *ops; + int err = 0; + + if ((err = genl_ctrl_alloc_cache(sk, &ctrl)) < 0) + goto errout; + + nl_list_for_each_entry(ops, &genl_ops_list, o_list) { + err = __genl_ops_resolve(ctrl, ops); + } + + nl_cache_free(ctrl); +errout: + return err; +} + +/** @} */ + + +/** @} */ diff --git a/libnetwork/libnl3/lib/handlers.c b/libnetwork/libnl3/lib/handlers.c new file mode 100644 index 0000000..f13b89e --- /dev/null +++ b/libnetwork/libnl3/lib/handlers.c @@ -0,0 +1,395 @@ +/* + * lib/handlers.c default netlink message handlers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup core + * @defgroup cb Callbacks/Customization + * + * @details + * @par 1) Setting up a callback set + * @code + * // Allocate a callback set and initialize it to the verbose default set + * struct nl_cb *cb = nl_cb_alloc(NL_CB_VERBOSE); + * + * // Modify the set to call my_func() for all valid messages + * nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL); + * + * // Set the error message handler to the verbose default implementation + * // and direct it to print all errors to the given file descriptor. + * FILE *file = fopen(...); + * nl_cb_err(cb, NL_CB_VERBOSE, NULL, file); + * @endcode + * @{ + */ + +#include +#include +#include +#include +#include + +static void print_header_content(FILE *ofd, struct nlmsghdr *n) +{ + char flags[128]; + char type[32]; + + fprintf(ofd, "type=%s length=%u flags=<%s> sequence-nr=%u pid=%u", + nl_nlmsgtype2str(n->nlmsg_type, type, sizeof(type)), + n->nlmsg_len, nl_nlmsg_flags2str(n->nlmsg_flags, flags, + sizeof(flags)), n->nlmsg_seq, n->nlmsg_pid); +} + +static int nl_valid_handler_verbose(struct nl_msg *msg, void *arg) +{ + FILE *ofd = arg ? arg : stdout; + + fprintf(ofd, "-- Warning: unhandled valid message: "); + print_header_content(ofd, nlmsg_hdr(msg)); + fprintf(ofd, "\n"); + + return NL_OK; +} + +static int nl_invalid_handler_verbose(struct nl_msg *msg, void *arg) +{ + FILE *ofd = arg ? arg : stderr; + + fprintf(ofd, "-- Error: Invalid message: "); + print_header_content(ofd, nlmsg_hdr(msg)); + fprintf(ofd, "\n"); + + return NL_STOP; +} + +static int nl_overrun_handler_verbose(struct nl_msg *msg, void *arg) +{ + FILE *ofd = arg ? arg : stderr; + + fprintf(ofd, "-- Error: Netlink Overrun: "); + print_header_content(ofd, nlmsg_hdr(msg)); + fprintf(ofd, "\n"); + + return NL_STOP; +} + +static int nl_error_handler_verbose(struct sockaddr_nl *who, + struct nlmsgerr *e, void *arg) +{ + FILE *ofd = arg ? arg : stderr; + + fprintf(ofd, "-- Error received: %s\n-- Original message: ", + strerror(-e->error)); + print_header_content(ofd, &e->msg); + fprintf(ofd, "\n"); + + return -nl_syserr2nlerr(e->error); +} + +static int nl_valid_handler_debug(struct nl_msg *msg, void *arg) +{ + FILE *ofd = arg ? arg : stderr; + + fprintf(ofd, "-- Debug: Unhandled Valid message: "); + print_header_content(ofd, nlmsg_hdr(msg)); + fprintf(ofd, "\n"); + + return NL_OK; +} + +static int nl_finish_handler_debug(struct nl_msg *msg, void *arg) +{ + FILE *ofd = arg ? arg : stderr; + + fprintf(ofd, "-- Debug: End of multipart message block: "); + print_header_content(ofd, nlmsg_hdr(msg)); + fprintf(ofd, "\n"); + + return NL_STOP; +} + +static int nl_msg_in_handler_debug(struct nl_msg *msg, void *arg) +{ + FILE *ofd = arg ? arg : stderr; + + fprintf(ofd, "-- Debug: Received Message:\n"); + nl_msg_dump(msg, ofd); + + return NL_OK; +} + +static int nl_msg_out_handler_debug(struct nl_msg *msg, void *arg) +{ + FILE *ofd = arg ? arg : stderr; + + fprintf(ofd, "-- Debug: Sent Message:\n"); + nl_msg_dump(msg, ofd); + + return NL_OK; +} + +static int nl_skipped_handler_debug(struct nl_msg *msg, void *arg) +{ + FILE *ofd = arg ? arg : stderr; + + fprintf(ofd, "-- Debug: Skipped message: "); + print_header_content(ofd, nlmsg_hdr(msg)); + fprintf(ofd, "\n"); + + return NL_SKIP; +} + +static int nl_ack_handler_debug(struct nl_msg *msg, void *arg) +{ + FILE *ofd = arg ? arg : stderr; + + fprintf(ofd, "-- Debug: ACK: "); + print_header_content(ofd, nlmsg_hdr(msg)); + fprintf(ofd, "\n"); + + return NL_STOP; +} + +static nl_recvmsg_msg_cb_t cb_def[NL_CB_TYPE_MAX+1][NL_CB_KIND_MAX+1] = { + [NL_CB_VALID] = { + [NL_CB_VERBOSE] = nl_valid_handler_verbose, + [NL_CB_DEBUG] = nl_valid_handler_debug, + }, + [NL_CB_FINISH] = { + [NL_CB_DEBUG] = nl_finish_handler_debug, + }, + [NL_CB_INVALID] = { + [NL_CB_VERBOSE] = nl_invalid_handler_verbose, + [NL_CB_DEBUG] = nl_invalid_handler_verbose, + }, + [NL_CB_MSG_IN] = { + [NL_CB_DEBUG] = nl_msg_in_handler_debug, + }, + [NL_CB_MSG_OUT] = { + [NL_CB_DEBUG] = nl_msg_out_handler_debug, + }, + [NL_CB_OVERRUN] = { + [NL_CB_VERBOSE] = nl_overrun_handler_verbose, + [NL_CB_DEBUG] = nl_overrun_handler_verbose, + }, + [NL_CB_SKIPPED] = { + [NL_CB_DEBUG] = nl_skipped_handler_debug, + }, + [NL_CB_ACK] = { + [NL_CB_DEBUG] = nl_ack_handler_debug, + }, +}; + +static nl_recvmsg_err_cb_t cb_err_def[NL_CB_KIND_MAX+1] = { + [NL_CB_VERBOSE] = nl_error_handler_verbose, + [NL_CB_DEBUG] = nl_error_handler_verbose, +}; + +/** + * @name Callback Handle Management + * @{ + */ + +/** + * Allocate a new callback handle + * @arg kind callback kind to be used for initialization + * @return Newly allocated callback handle or NULL + */ +struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind) +{ + int i; + struct nl_cb *cb; + + if (kind < 0 || kind > NL_CB_KIND_MAX) + return NULL; + + cb = calloc(1, sizeof(*cb)); + if (!cb) + return NULL; + + cb->cb_refcnt = 1; + + for (i = 0; i <= NL_CB_TYPE_MAX; i++) + nl_cb_set(cb, i, kind, NULL, NULL); + + nl_cb_err(cb, kind, NULL, NULL); + + return cb; +} + +/** + * Clone an existing callback handle + * @arg orig original callback handle + * @return Newly allocated callback handle being a duplicate of + * orig or NULL + */ +struct nl_cb *nl_cb_clone(struct nl_cb *orig) +{ + struct nl_cb *cb; + + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) + return NULL; + + memcpy(cb, orig, sizeof(*orig)); + cb->cb_refcnt = 1; + + return cb; +} + +struct nl_cb *nl_cb_get(struct nl_cb *cb) +{ + cb->cb_refcnt++; + + return cb; +} + +void nl_cb_put(struct nl_cb *cb) +{ + if (!cb) + return; + + cb->cb_refcnt--; + + if (cb->cb_refcnt < 0) + BUG(); + + if (cb->cb_refcnt <= 0) + free(cb); +} + +/** @} */ + +/** + * @name Callback Setup + * @{ + */ + +/** + * Set up a callback + * @arg cb callback set + * @arg type callback to modify + * @arg kind kind of implementation + * @arg func callback function (NL_CB_CUSTOM) + * @arg arg argument passed to callback + * + * @return 0 on success or a negative error code + */ +int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind, + nl_recvmsg_msg_cb_t func, void *arg) +{ + if (type < 0 || type > NL_CB_TYPE_MAX) + return -NLE_RANGE; + + if (kind < 0 || kind > NL_CB_KIND_MAX) + return -NLE_RANGE; + + if (kind == NL_CB_CUSTOM) { + cb->cb_set[type] = func; + cb->cb_args[type] = arg; + } else { + cb->cb_set[type] = cb_def[type][kind]; + cb->cb_args[type] = arg; + } + + return 0; +} + +/** + * Set up a all callbacks + * @arg cb callback set + * @arg kind kind of callback + * @arg func callback function + * @arg arg argument to be passwd to callback function + * + * @return 0 on success or a negative error code + */ +int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind, + nl_recvmsg_msg_cb_t func, void *arg) +{ + int i, err; + + for (i = 0; i <= NL_CB_TYPE_MAX; i++) { + err = nl_cb_set(cb, i, kind, func, arg); + if (err < 0) + return err; + } + + return 0; +} + +/** + * Set up an error callback + * @arg cb callback set + * @arg kind kind of callback + * @arg func callback function + * @arg arg argument to be passed to callback function + */ +int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind, + nl_recvmsg_err_cb_t func, void *arg) +{ + if (kind < 0 || kind > NL_CB_KIND_MAX) + return -NLE_RANGE; + + if (kind == NL_CB_CUSTOM) { + cb->cb_err = func; + cb->cb_err_arg = arg; + } else { + cb->cb_err = cb_err_def[kind]; + cb->cb_err_arg = arg; + } + + return 0; +} + +/** @} */ + +/** + * @name Overwriting + * @{ + */ + +/** + * Overwrite internal calls to nl_recvmsgs() + * @arg cb callback set + * @arg func replacement callback for nl_recvmsgs() + */ +void nl_cb_overwrite_recvmsgs(struct nl_cb *cb, + int (*func)(struct nl_sock *, struct nl_cb *)) +{ + cb->cb_recvmsgs_ow = func; +} + +/** + * Overwrite internal calls to nl_recv() + * @arg cb callback set + * @arg func replacement callback for nl_recv() + */ +void nl_cb_overwrite_recv(struct nl_cb *cb, + int (*func)(struct nl_sock *, struct sockaddr_nl *, + unsigned char **, struct ucred **)) +{ + cb->cb_recv_ow = func; +} + +/** + * Overwrite internal calls to nl_send() + * @arg cb callback set + * @arg func replacement callback for nl_send() + */ +void nl_cb_overwrite_send(struct nl_cb *cb, + int (*func)(struct nl_sock *, struct nl_msg *)) +{ + cb->cb_send_ow = func; +} + +/** @} */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/msg.c b/libnetwork/libnl3/lib/msg.c new file mode 100644 index 0000000..235ee82 --- /dev/null +++ b/libnetwork/libnl3/lib/msg.c @@ -0,0 +1,1050 @@ +/* + * lib/msg.c Netlink Messages Interface + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup core + * @defgroup msg Messages + * Netlink Message Construction/Parsing Interface + * + * The following information is partly extracted from RFC3549 + * (ftp://ftp.rfc-editor.org/in-notes/rfc3549.txt) + * + * @par Message Format + * Netlink messages consist of a byte stream with one or multiple + * Netlink headers and an associated payload. If the payload is too big + * to fit into a single message it, can be split over multiple Netlink + * messages, collectively called a multipart message. For multipart + * messages, the first and all following headers have the \c NLM_F_MULTI + * Netlink header flag set, except for the last header which has the + * Netlink header type \c NLMSG_DONE. + * + * @par + * The Netlink message header (struct nlmsghdr) is shown below. + * @code + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Flags | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Process ID (PID) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * @endcode + * + * @par + * The netlink message header and payload must be aligned properly: + * @code + * <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) ---> + * +----------------------------+- - -+- - - - - - - - - - -+- - -+ + * | Header | Pad | Payload | Pad | + * | struct nlmsghdr | | | | + * +----------------------------+- - -+- - - - - - - - - - -+- - -+ + * @endcode + * @par + * Message Format: + * @code + * <--- nlmsg_total_size(payload) ---> + * <-- nlmsg_msg_size(payload) -> + * +----------+- - -+-------------+- - -+-------- - - + * | nlmsghdr | Pad | Payload | Pad | nlmsghdr + * +----------+- - -+-------------+- - -+-------- - - + * nlmsg_data(nlh)---^ ^ + * nlmsg_next(nlh)-----------------------+ + * @endcode + * @par + * The payload may consist of arbitary data but may have strict + * alignment and formatting rules depening on the specific netlink + * families. + * @par + * @code + * <---------------------- nlmsg_len(nlh) ---------------------> + * <------ hdrlen ------> <- nlmsg_attrlen(nlh, hdrlen) -> + * +----------------------+- - -+--------------------------------+ + * | Family Header | Pad | Attributes | + * +----------------------+- - -+--------------------------------+ + * nlmsg_attrdata(nlh, hdrlen)---^ + * @endcode + * @par The ACK Netlink Message + * This message is actually used to denote both an ACK and a NACK. + * Typically, the direction is from FEC to CPC (in response to an ACK + * request message). However, the CPC should be able to send ACKs back + * to FEC when requested. + * @code + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Netlink message header | + * | type = NLMSG_ERROR | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Error code | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OLD Netlink message header | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * @endcode + * + * @par Example + * @code + * // Various methods exist to create/allocate a new netlink + * // message. + * // + * // nlmsg_alloc() will allocate an empty netlink message with + * // a maximum payload size which defaults to the page size of + * // the system. This default size can be modified using the + * // function nlmsg_set_default_size(). + * struct nl_msg *msg = nlmsg_alloc(); + * + * // Very often, the message type and message flags are known + * // at allocation time while the other fields are auto generated: + * struct nl_msg *msg = nlmsg_alloc_simple(MY_TYPE, MY_FLAGS); + * + * // Alternatively an existing netlink message header can be used + * // to inherit the header values: + * struct nlmsghdr hdr = { + * .nlmsg_type = MY_TYPE, + * .nlmsg_flags = MY_FLAGS, + * }; + * struct nl_msg *msg = nlmsg_inherit(&hdr); + * + * // Last but not least, netlink messages received from netlink sockets + * // can be converted into nl_msg objects using nlmsg_convert(). This + * // will create a message with a maximum payload size which equals the + * // length of the existing netlink message, therefore no more data can + * // be appened without calling nlmsg_expand() first. + * struct nl_msg *msg = nlmsg_convert(nlh_from_nl_sock); + * + * // Payload may be added to the message via nlmsg_append(). The fourth + * // parameter specifies the number of alignment bytes the data should + * // be padding with at the end. Common values are 0 to disable it or + * // NLMSG_ALIGNTO to ensure proper netlink message padding. + * nlmsg_append(msg, &mydata, sizeof(mydata), 0); + * + * // Sometimes it may be necessary to reserve room for data but defer + * // the actual copying to a later point, nlmsg_reserve() can be used + * // for this purpose: + * void *data = nlmsg_reserve(msg, sizeof(mydata), NLMSG_ALIGNTO); + * + * // Attributes may be added using the attributes interface. + * + * // After successful use of the message, the memory must be freed + * // using nlmsg_free() + * nlmsg_free(msg); + * @endcode + * + * @par 4) Parsing messages + * @code + * int n; + * unsigned char *buf; + * struct nlmsghdr *hdr; + * + * n = nl_recv(handle, NULL, &buf); + * + * hdr = (struct nlmsghdr *) buf; + * while (nlmsg_ok(hdr, n)) { + * // Process message here... + * hdr = nlmsg_next(hdr, &n); + * } + * @endcode + * @{ + */ + +#include +#include +#include +#include +#include +#include + +static size_t default_msg_size; + +static void __init init_msg_size(void) +{ + default_msg_size = getpagesize(); +} + +/** + * @name Size Calculations + * @{ + */ + +/** + * Calculates size of netlink message based on payload length. + * @arg payload Length of payload + * + * @return size of netlink message without padding. + */ +int nlmsg_size(int payload) +{ + return NLMSG_HDRLEN + payload; +} + +static int nlmsg_msg_size(int payload) +{ + return nlmsg_size(payload); +} + +/** + * Calculates size of netlink message including padding based on payload length + * @arg payload Length of payload + * + * This function is idential to nlmsg_size() + nlmsg_padlen(). + * + * @return Size of netlink message including padding. + */ +int nlmsg_total_size(int payload) +{ + return NLMSG_ALIGN(nlmsg_msg_size(payload)); +} + +/** + * Size of padding that needs to be added at end of message + * @arg payload Length of payload + * + * Calculates the number of bytes of padding which is required to be added to + * the end of the message to ensure that the next netlink message header begins + * properly aligned to NLMSG_ALIGNTO. + * + * @return Number of bytes of padding needed. + */ +int nlmsg_padlen(int payload) +{ + return nlmsg_total_size(payload) - nlmsg_msg_size(payload); +} + +/** @} */ + +/** + * @name Access to Message Payload + * @{ + */ + +/** + * Return pointer to message payload + * @arg nlh Netlink message header + * + * @return Pointer to start of message payload. + */ +void *nlmsg_data(const struct nlmsghdr *nlh) +{ + return (unsigned char *) nlh + NLMSG_HDRLEN; +} + +void *nlmsg_tail(const struct nlmsghdr *nlh) +{ + return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len); +} + +/** + * Return length of message payload + * @arg nlh Netlink message header + * + * @return Length of message payload in bytes. + */ +int nlmsg_datalen(const struct nlmsghdr *nlh) +{ + return nlh->nlmsg_len - NLMSG_HDRLEN; +} + +static int nlmsg_len(const struct nlmsghdr *nlh) +{ + return nlmsg_datalen(nlh); +} + +/** @} */ + +/** + * @name Attribute Access + * @{ + */ + +/** + * head of attributes data + * @arg nlh netlink message header + * @arg hdrlen length of family specific header + */ +struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen) +{ + unsigned char *data = nlmsg_data(nlh); + return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen)); +} + +/** + * length of attributes data + * @arg nlh netlink message header + * @arg hdrlen length of family specific header + */ +int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen) +{ + return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen); +} + +/** @} */ + +/** + * @name Message Parsing + * @{ + */ + +int nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen) +{ + if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) + return 0; + + return 1; +} + +/** + * check if the netlink message fits into the remaining bytes + * @arg nlh netlink message header + * @arg remaining number of bytes remaining in message stream + */ +int nlmsg_ok(const struct nlmsghdr *nlh, int remaining) +{ + return (remaining >= (int)sizeof(struct nlmsghdr) && + nlh->nlmsg_len >= sizeof(struct nlmsghdr) && + nlh->nlmsg_len <= remaining); +} + +/** + * next netlink message in message stream + * @arg nlh netlink message header + * @arg remaining number of bytes remaining in message stream + * + * @returns the next netlink message in the message stream and + * decrements remaining by the size of the current message. + */ +struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining) +{ + int totlen = NLMSG_ALIGN(nlh->nlmsg_len); + + *remaining -= totlen; + + return (struct nlmsghdr *) ((unsigned char *) nlh + totlen); +} + +/** + * parse attributes of a netlink message + * @arg nlh netlink message header + * @arg hdrlen length of family specific header + * @arg tb destination array with maxtype+1 elements + * @arg maxtype maximum attribute type to be expected + * @arg policy validation policy + * + * See nla_parse() + */ +int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], + int maxtype, struct nla_policy *policy) +{ + if (!nlmsg_valid_hdr(nlh, hdrlen)) + return -NLE_MSG_TOOSHORT; + + return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), + nlmsg_attrlen(nlh, hdrlen), policy); +} + +/** + * nlmsg_find_attr - find a specific attribute in a netlink message + * @arg nlh netlink message header + * @arg hdrlen length of familiy specific header + * @arg attrtype type of attribute to look for + * + * Returns the first attribute which matches the specified type. + */ +struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype) +{ + return nla_find(nlmsg_attrdata(nlh, hdrlen), + nlmsg_attrlen(nlh, hdrlen), attrtype); +} + +/** + * nlmsg_validate - validate a netlink message including attributes + * @arg nlh netlinket message header + * @arg hdrlen length of familiy specific header + * @arg maxtype maximum attribute type to be expected + * @arg policy validation policy + */ +int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype, + struct nla_policy *policy) +{ + if (!nlmsg_valid_hdr(nlh, hdrlen)) + return -NLE_MSG_TOOSHORT; + + return nla_validate(nlmsg_attrdata(nlh, hdrlen), + nlmsg_attrlen(nlh, hdrlen), maxtype, policy); +} + +/** @} */ + +/** + * @name Message Building/Access + * @{ + */ + +static struct nl_msg *__nlmsg_alloc(size_t len) +{ + struct nl_msg *nm; + + if (len < sizeof(struct nlmsghdr)) + len = sizeof(struct nlmsghdr); + + nm = calloc(1, sizeof(*nm)); + if (!nm) + goto errout; + + nm->nm_refcnt = 1; + + nm->nm_nlh = calloc(1, len); + if (!nm->nm_nlh) + goto errout; + + memset(nm->nm_nlh, 0, sizeof(struct nlmsghdr)); + + nm->nm_protocol = -1; + nm->nm_size = len; + nm->nm_nlh->nlmsg_len = nlmsg_total_size(0); + + NL_DBG(2, "msg %p: Allocated new message, maxlen=%zu\n", nm, len); + + return nm; +errout: + free(nm); + return NULL; +} + +/** + * Allocate a new netlink message with the default maximum payload size. + * + * Allocates a new netlink message without any further payload. The + * maximum payload size defaults to PAGESIZE or as otherwise specified + * with nlmsg_set_default_size(). + * + * @return Newly allocated netlink message or NULL. + */ +struct nl_msg *nlmsg_alloc(void) +{ + return __nlmsg_alloc(default_msg_size); +} + +/** + * Allocate a new netlink message with maximum payload size specified. + */ +struct nl_msg *nlmsg_alloc_size(size_t max) +{ + return __nlmsg_alloc(max); +} + +/** + * Allocate a new netlink message and inherit netlink message header + * @arg hdr Netlink message header template + * + * Allocates a new netlink message and inherits the original message + * header. If \a hdr is not NULL it will be used as a template for + * the netlink message header, otherwise the header is left blank. + * + * @return Newly allocated netlink message or NULL + */ +struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr) +{ + struct nl_msg *nm; + + nm = nlmsg_alloc(); + if (nm && hdr) { + struct nlmsghdr *new = nm->nm_nlh; + + new->nlmsg_type = hdr->nlmsg_type; + new->nlmsg_flags = hdr->nlmsg_flags; + new->nlmsg_seq = hdr->nlmsg_seq; + new->nlmsg_pid = hdr->nlmsg_pid; + } + + return nm; +} + +/** + * Allocate a new netlink message + * @arg nlmsgtype Netlink message type + * @arg flags Message flags. + * + * @return Newly allocated netlink message or NULL. + */ +struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags) +{ + struct nl_msg *msg; + struct nlmsghdr nlh = { + .nlmsg_type = nlmsgtype, + .nlmsg_flags = flags, + }; + + msg = nlmsg_inherit(&nlh); + if (msg) + NL_DBG(2, "msg %p: Allocated new simple message\n", msg); + + return msg; +} + +/** + * Set the default maximum message payload size for allocated messages + * @arg max Size of payload in bytes. + */ +void nlmsg_set_default_size(size_t max) +{ + if (max < nlmsg_total_size(0)) + max = nlmsg_total_size(0); + + default_msg_size = max; +} + +/** + * Convert a netlink message received from a netlink socket to a nl_msg + * @arg hdr Netlink message received from netlink socket. + * + * Allocates a new netlink message and copies all of the data pointed to + * by \a hdr into the new message object. + * + * @return Newly allocated netlink message or NULL. + */ +struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr) +{ + struct nl_msg *nm; + + nm = __nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len)); + if (!nm) + goto errout; + + memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len); + + return nm; +errout: + nlmsg_free(nm); + return NULL; +} + +/** + * Reserve room for additional data in a netlink message + * @arg n netlink message + * @arg len length of additional data to reserve room for + * @arg pad number of bytes to align data to + * + * Reserves room for additional data at the tail of the an + * existing netlink message. Eventual padding required will + * be zeroed out. + * + * @return Pointer to start of additional data tailroom or NULL. + */ +void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad) +{ + void *buf = n->nm_nlh; + size_t nlmsg_len = n->nm_nlh->nlmsg_len; + size_t tlen; + + tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len; + + if ((tlen + nlmsg_len) > n->nm_size) + return NULL; + + buf += nlmsg_len; + n->nm_nlh->nlmsg_len += tlen; + + if (tlen > len) + memset(buf + len, 0, tlen - len); + + NL_DBG(2, "msg %p: Reserved %zu (%zu) bytes, pad=%d, nlmsg_len=%d\n", + n, tlen, len, pad, n->nm_nlh->nlmsg_len); + + return buf; +} + +/** + * Append data to tail of a netlink message + * @arg n netlink message + * @arg data data to add + * @arg len length of data + * @arg pad Number of bytes to align data to. + * + * Extends the netlink message as needed and appends the data of given + * length to the message. + * + * @return 0 on success or a negative error code + */ +int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad) +{ + void *tmp; + + tmp = nlmsg_reserve(n, len, pad); + if (tmp == NULL) + return -NLE_NOMEM; + + memcpy(tmp, data, len); + NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad); + + return 0; +} + +/** + * Expand maximum payload size of a netlink message + * @arg n Netlink message. + * @arg newlen New maximum payload size. + * + * Reallocates the payload section of a netlink message and increases + * the maximum payload size of the message. + * + * @note Any pointers pointing to old payload block will be stale and + * need to be refetched. Therfore, do not expand while constructing + * nested attributes or while reserved data blocks are held. + * + * @return 0 on success or a negative error code. + */ +int nlmsg_expand(struct nl_msg *n, size_t newlen) +{ + void *tmp; + + if (newlen <= n->nm_size) + return -NLE_INVAL; + + tmp = realloc(n->nm_nlh, newlen); + if (tmp == NULL) + return -NLE_NOMEM; + + n->nm_nlh = tmp; + n->nm_size = newlen; + + return 0; +} + +/** + * Add a netlink message header to a netlink message + * @arg n netlink message + * @arg pid netlink process id or NL_AUTO_PID + * @arg seq sequence number of message or NL_AUTO_SEQ + * @arg type message type + * @arg payload length of message payload + * @arg flags message flags + * + * Adds or overwrites the netlink message header in an existing message + * object. If \a payload is greater-than zero additional room will be + * reserved, f.e. for family specific headers. It can be accesed via + * nlmsg_data(). + * + * @return A pointer to the netlink message header or NULL. + */ +struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, + int type, int payload, int flags) +{ + struct nlmsghdr *nlh; + + if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN) + BUG(); + + nlh = (struct nlmsghdr *) n->nm_nlh; + nlh->nlmsg_type = type; + nlh->nlmsg_flags = flags; + nlh->nlmsg_pid = pid; + nlh->nlmsg_seq = seq; + + NL_DBG(2, "msg %p: Added netlink header type=%d, flags=%d, pid=%d, " + "seq=%d\n", n, type, flags, pid, seq); + + if (payload > 0 && + nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL) + return NULL; + + return nlh; +} + +/** + * Return actual netlink message + * @arg n netlink message + * + * Returns the actual netlink message casted to the type of the netlink + * message header. + * + * @return A pointer to the netlink message. + */ +struct nlmsghdr *nlmsg_hdr(struct nl_msg *n) +{ + return n->nm_nlh; +} + +/** + * Acquire a reference on a netlink message + * @arg msg message to acquire reference from + */ +void nlmsg_get(struct nl_msg *msg) +{ + msg->nm_refcnt++; + NL_DBG(4, "New reference to message %p, total %d\n", + msg, msg->nm_refcnt); +} + +/** + * Release a reference from an netlink message + * @arg msg message to release reference from + * + * Frees memory after the last reference has been released. + */ +void nlmsg_free(struct nl_msg *msg) +{ + if (!msg) + return; + + msg->nm_refcnt--; + NL_DBG(4, "Returned message reference %p, %d remaining\n", + msg, msg->nm_refcnt); + + if (msg->nm_refcnt < 0) + BUG(); + + if (msg->nm_refcnt <= 0) { + free(msg->nm_nlh); + free(msg); + NL_DBG(2, "msg %p: Freed\n", msg); + } +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void nlmsg_set_proto(struct nl_msg *msg, int protocol) +{ + msg->nm_protocol = protocol; +} + +int nlmsg_get_proto(struct nl_msg *msg) +{ + return msg->nm_protocol; +} + +size_t nlmsg_get_max_size(struct nl_msg *msg) +{ + return msg->nm_size; +} + +void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr) +{ + memcpy(&msg->nm_src, addr, sizeof(*addr)); +} + +struct sockaddr_nl *nlmsg_get_src(struct nl_msg *msg) +{ + return &msg->nm_src; +} + +void nlmsg_set_dst(struct nl_msg *msg, struct sockaddr_nl *addr) +{ + memcpy(&msg->nm_dst, addr, sizeof(*addr)); +} + +struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg) +{ + return &msg->nm_dst; +} + +void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds) +{ + memcpy(&msg->nm_creds, creds, sizeof(*creds)); + msg->nm_flags |= NL_MSG_CRED_PRESENT; +} + +struct ucred *nlmsg_get_creds(struct nl_msg *msg) +{ + if (msg->nm_flags & NL_MSG_CRED_PRESENT) + return &msg->nm_creds; + return NULL; +} + +/** @} */ + +/** + * @name Netlink Message Type Translations + * @{ + */ + +static const struct trans_tbl nl_msgtypes[] = { + __ADD(NLMSG_NOOP,NOOP) + __ADD(NLMSG_ERROR,ERROR) + __ADD(NLMSG_DONE,DONE) + __ADD(NLMSG_OVERRUN,OVERRUN) +}; + +char *nl_nlmsgtype2str(int type, char *buf, size_t size) +{ + return __type2str(type, buf, size, nl_msgtypes, + ARRAY_SIZE(nl_msgtypes)); +} + +int nl_str2nlmsgtype(const char *name) +{ + return __str2type(name, nl_msgtypes, ARRAY_SIZE(nl_msgtypes)); +} + +/** @} */ + +/** + * @name Netlink Message Flags Translations + * @{ + */ + +char *nl_nlmsg_flags2str(int flags, char *buf, size_t len) +{ + memset(buf, 0, len); + +#define PRINT_FLAG(f) \ + if (flags & NLM_F_##f) { \ + flags &= ~NLM_F_##f; \ + strncat(buf, #f, len - strlen(buf) - 1); \ + if (flags) \ + strncat(buf, ",", len - strlen(buf) - 1); \ + } + + PRINT_FLAG(REQUEST); + PRINT_FLAG(MULTI); + PRINT_FLAG(ACK); + PRINT_FLAG(ECHO); + PRINT_FLAG(ROOT); + PRINT_FLAG(MATCH); + PRINT_FLAG(ATOMIC); + PRINT_FLAG(REPLACE); + PRINT_FLAG(EXCL); + PRINT_FLAG(CREATE); + PRINT_FLAG(APPEND); + + if (flags) { + char s[32]; + snprintf(s, sizeof(s), "0x%x", flags); + strncat(buf, s, len - strlen(buf) - 1); + } +#undef PRINT_FLAG + + return buf; +} + +/** @} */ + +/** + * @name Direct Parsing + * @{ + */ + +/** @cond SKIP */ +struct dp_xdata { + void (*cb)(struct nl_object *, void *); + void *arg; +}; +/** @endcond */ + +static int parse_cb(struct nl_object *obj, struct nl_parser_param *p) +{ + struct dp_xdata *x = p->pp_arg; + + x->cb(obj, x->arg); + return 0; +} + +int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *), + void *arg) +{ + struct nl_cache_ops *ops; + struct nl_parser_param p = { + .pp_cb = parse_cb + }; + struct dp_xdata x = { + .cb = cb, + .arg = arg, + }; + + ops = nl_cache_ops_associate(nlmsg_get_proto(msg), + nlmsg_hdr(msg)->nlmsg_type); + if (ops == NULL) + return -NLE_MSGTYPE_NOSUPPORT; + p.pp_arg = &x; + + return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p); +} + +/** @} */ + +/** + * @name Dumping + * @{ + */ + +static void prefix_line(FILE *ofd, int prefix) +{ + int i; + + for (i = 0; i < prefix; i++) + fprintf(ofd, " "); +} + +static inline void dump_hex(FILE *ofd, char *start, int len, int prefix) +{ + int i, a, c, limit; + char ascii[21] = {0}; + + limit = 18 - (prefix * 2); + prefix_line(ofd, prefix); + fprintf(ofd, " "); + + for (i = 0, a = 0, c = 0; i < len; i++) { + int v = *(uint8_t *) (start + i); + + fprintf(ofd, "%02x ", v); + ascii[a++] = isprint(v) ? v : '.'; + + if (c == limit-1) { + fprintf(ofd, "%s\n", ascii); + if (i < (len - 1)) { + prefix_line(ofd, prefix); + fprintf(ofd, " "); + } + a = c = 0; + memset(ascii, 0, sizeof(ascii)); + } else + c++; + } + + if (c != 0) { + for (i = 0; i < (limit - c); i++) + fprintf(ofd, " "); + fprintf(ofd, "%s\n", ascii); + } +} + +static void print_hdr(FILE *ofd, struct nl_msg *msg) +{ + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct nl_cache_ops *ops; + struct nl_msgtype *mt; + char buf[128]; + + fprintf(ofd, " .nlmsg_len = %d\n", nlh->nlmsg_len); + + ops = nl_cache_ops_associate(nlmsg_get_proto(msg), nlh->nlmsg_type); + if (ops) { + mt = nl_msgtype_lookup(ops, nlh->nlmsg_type); + if (!mt) + BUG(); + + snprintf(buf, sizeof(buf), "%s::%s", ops->co_name, mt->mt_name); + } else + nl_nlmsgtype2str(nlh->nlmsg_type, buf, sizeof(buf)); + + fprintf(ofd, " .nlmsg_type = %d <%s>\n", nlh->nlmsg_type, buf); + fprintf(ofd, " .nlmsg_flags = %d <%s>\n", nlh->nlmsg_flags, + nl_nlmsg_flags2str(nlh->nlmsg_flags, buf, sizeof(buf))); + fprintf(ofd, " .nlmsg_seq = %d\n", nlh->nlmsg_seq); + fprintf(ofd, " .nlmsg_pid = %d\n", nlh->nlmsg_pid); + +} + +static void dump_attrs(FILE *ofd, struct nlattr *attrs, int attrlen, + int prefix) +{ + int rem; + struct nlattr *nla; + + nla_for_each_attr(nla, attrs, attrlen, rem) { + int padlen, alen = nla_len(nla); + + prefix_line(ofd, prefix); + fprintf(ofd, " [ATTR %02d%s] %d octets\n", nla_type(nla), + nla->nla_type & NLA_F_NESTED ? " NESTED" : "", + alen); + + if (nla->nla_type & NLA_F_NESTED) + dump_attrs(ofd, nla_data(nla), alen, prefix+1); + else + dump_hex(ofd, nla_data(nla), alen, prefix); + + padlen = nla_padlen(alen); + if (padlen > 0) { + prefix_line(ofd, prefix); + fprintf(ofd, " [PADDING] %d octets\n", + padlen); + dump_hex(ofd, nla_data(nla) + alen, + padlen, prefix); + } + } + + if (rem) { + prefix_line(ofd, prefix); + fprintf(ofd, " [LEFTOVER] %d octets\n", rem); + } +} + +/** + * Dump message in human readable format to file descriptor + * @arg msg Message to print + * @arg ofd File descriptor. + */ +void nl_msg_dump(struct nl_msg *msg, FILE *ofd) +{ + struct nlmsghdr *hdr = nlmsg_hdr(msg); + + fprintf(ofd, + "-------------------------- BEGIN NETLINK MESSAGE " + "---------------------------\n"); + + fprintf(ofd, " [HEADER] %Zu octets\n", sizeof(struct nlmsghdr)); + print_hdr(ofd, msg); + + if (hdr->nlmsg_type == NLMSG_ERROR && + hdr->nlmsg_len >= nlmsg_msg_size(sizeof(struct nlmsgerr))) { + struct nl_msg *errmsg; + struct nlmsgerr *err = nlmsg_data(hdr); + + fprintf(ofd, " [ERRORMSG] %Zu octets\n", sizeof(*err)); + fprintf(ofd, " .error = %d \"%s\"\n", err->error, + strerror(-err->error)); + fprintf(ofd, " [ORIGINAL MESSAGE] %Zu octets\n", sizeof(*hdr)); + + errmsg = nlmsg_inherit(&err->msg); + print_hdr(ofd, errmsg); + nlmsg_free(errmsg); + } else if (nlmsg_len(hdr) > 0) { + struct nl_cache_ops *ops; + int payloadlen = nlmsg_len(hdr); + int attrlen = 0; + + ops = nl_cache_ops_associate(nlmsg_get_proto(msg), + hdr->nlmsg_type); + if (ops) { + attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize); + payloadlen -= attrlen; + } + + fprintf(ofd, " [PAYLOAD] %d octets\n", payloadlen); + dump_hex(ofd, nlmsg_data(hdr), payloadlen, 0); + + if (attrlen) { + struct nlattr *attrs; + int attrlen; + + attrs = nlmsg_attrdata(hdr, ops->co_hdrsize); + attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize); + dump_attrs(ofd, attrs, attrlen, 0); + } + } + + fprintf(ofd, + "--------------------------- END NETLINK MESSAGE " + "---------------------------\n"); +} + +/** @} */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/netfilter/.dirstamp b/libnetwork/libnl3/lib/netfilter/.dirstamp new file mode 100644 index 0000000..e69de29 diff --git a/libnetwork/libnl3/lib/netfilter/ct.c b/libnetwork/libnl3/lib/netfilter/ct.c new file mode 100644 index 0000000..9d61b6c --- /dev/null +++ b/libnetwork/libnl3/lib/netfilter/ct.c @@ -0,0 +1,601 @@ +/* + * lib/netfilter/ct.c Conntrack + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + * Copyright (c) 2007 Philip Craig + * Copyright (c) 2007 Secure Computing Corporation + * Copyright (c= 2008 Patrick McHardy + */ + +/** + * @ingroup nfnl + * @defgroup ct Conntrack + * @brief + * @{ + */ + +#include +#include +#include + +#include +#include +#include +#include + +static struct nl_cache_ops nfnl_ct_ops; + +#if __BYTE_ORDER == __BIG_ENDIAN +static uint64_t ntohll(uint64_t x) +{ + return x; +} +#elif __BYTE_ORDER == __LITTLE_ENDIAN +static uint64_t ntohll(uint64_t x) +{ + return __bswap_64(x); +} +#endif + +static struct nla_policy ct_policy[CTA_MAX+1] = { + [CTA_TUPLE_ORIG] = { .type = NLA_NESTED }, + [CTA_TUPLE_REPLY] = { .type = NLA_NESTED }, + [CTA_STATUS] = { .type = NLA_U32 }, + [CTA_PROTOINFO] = { .type = NLA_NESTED }, + //[CTA_HELP] + //[CTA_NAT_SRC] + [CTA_TIMEOUT] = { .type = NLA_U32 }, + [CTA_MARK] = { .type = NLA_U32 }, + [CTA_COUNTERS_ORIG] = { .type = NLA_NESTED }, + [CTA_COUNTERS_REPLY] = { .type = NLA_NESTED }, + [CTA_USE] = { .type = NLA_U32 }, + [CTA_ID] = { .type = NLA_U32 }, + //[CTA_NAT_DST] +}; + +static struct nla_policy ct_tuple_policy[CTA_TUPLE_MAX+1] = { + [CTA_TUPLE_IP] = { .type = NLA_NESTED }, + [CTA_TUPLE_PROTO] = { .type = NLA_NESTED }, +}; + +static struct nla_policy ct_ip_policy[CTA_IP_MAX+1] = { + [CTA_IP_V4_SRC] = { .type = NLA_U32 }, + [CTA_IP_V4_DST] = { .type = NLA_U32 }, + [CTA_IP_V6_SRC] = { .minlen = 16 }, + [CTA_IP_V6_DST] = { .minlen = 16 }, +}; + +static struct nla_policy ct_proto_policy[CTA_PROTO_MAX+1] = { + [CTA_PROTO_NUM] = { .type = NLA_U8 }, + [CTA_PROTO_SRC_PORT] = { .type = NLA_U16 }, + [CTA_PROTO_DST_PORT] = { .type = NLA_U16 }, + [CTA_PROTO_ICMP_ID] = { .type = NLA_U16 }, + [CTA_PROTO_ICMP_TYPE] = { .type = NLA_U8 }, + [CTA_PROTO_ICMP_CODE] = { .type = NLA_U8 }, + [CTA_PROTO_ICMPV6_ID] = { .type = NLA_U16 }, + [CTA_PROTO_ICMPV6_TYPE] = { .type = NLA_U8 }, + [CTA_PROTO_ICMPV6_CODE] = { .type = NLA_U8 }, +}; + +static struct nla_policy ct_protoinfo_policy[CTA_PROTOINFO_MAX+1] = { + [CTA_PROTOINFO_TCP] = { .type = NLA_NESTED }, +}; + +static struct nla_policy ct_protoinfo_tcp_policy[CTA_PROTOINFO_TCP_MAX+1] = { + [CTA_PROTOINFO_TCP_STATE] = { .type = NLA_U8 }, + [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] = { .type = NLA_U8 }, + [CTA_PROTOINFO_TCP_WSCALE_REPLY] = { .type = NLA_U8 }, + [CTA_PROTOINFO_TCP_FLAGS_ORIGINAL] = { .minlen = 2 }, + [CTA_PROTOINFO_TCP_FLAGS_REPLY] = { .minlen = 2 }, + +}; + +static struct nla_policy ct_counters_policy[CTA_COUNTERS_MAX+1] = { + [CTA_COUNTERS_PACKETS] = { .type = NLA_U64 }, + [CTA_COUNTERS_BYTES] = { .type = NLA_U64 }, + [CTA_COUNTERS32_PACKETS]= { .type = NLA_U32 }, + [CTA_COUNTERS32_BYTES] = { .type = NLA_U32 }, +}; + +static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr) +{ + struct nlattr *tb[CTA_IP_MAX+1]; + struct nl_addr *addr; + int err; + + err = nla_parse_nested(tb, CTA_IP_MAX, attr, ct_ip_policy); + if (err < 0) + goto errout; + + if (tb[CTA_IP_V4_SRC]) { + addr = nl_addr_alloc_attr(tb[CTA_IP_V4_SRC], AF_INET); + if (addr == NULL) + goto errout_enomem; + err = nfnl_ct_set_src(ct, repl, addr); + nl_addr_put(addr); + if (err < 0) + goto errout; + } + if (tb[CTA_IP_V4_DST]) { + addr = nl_addr_alloc_attr(tb[CTA_IP_V4_DST], AF_INET); + if (addr == NULL) + goto errout_enomem; + err = nfnl_ct_set_dst(ct, repl, addr); + nl_addr_put(addr); + if (err < 0) + goto errout; + } + if (tb[CTA_IP_V6_SRC]) { + addr = nl_addr_alloc_attr(tb[CTA_IP_V6_SRC], AF_INET6); + if (addr == NULL) + goto errout_enomem; + err = nfnl_ct_set_src(ct, repl, addr); + nl_addr_put(addr); + if (err < 0) + goto errout; + } + if (tb[CTA_IP_V6_DST]) { + addr = nl_addr_alloc_attr(tb[CTA_IP_V6_DST], AF_INET6); + if (addr == NULL) + goto errout_enomem; + err = nfnl_ct_set_dst(ct, repl, addr); + nl_addr_put(addr); + if (err < 0) + goto errout; + } + + return 0; + +errout_enomem: + err = -NLE_NOMEM; +errout: + return err; +} + +static int ct_parse_proto(struct nfnl_ct *ct, int repl, struct nlattr *attr) +{ + struct nlattr *tb[CTA_PROTO_MAX+1]; + int err; + + err = nla_parse_nested(tb, CTA_PROTO_MAX, attr, ct_proto_policy); + if (err < 0) + return err; + + if (!repl && tb[CTA_PROTO_NUM]) + nfnl_ct_set_proto(ct, nla_get_u8(tb[CTA_PROTO_NUM])); + if (tb[CTA_PROTO_SRC_PORT]) + nfnl_ct_set_src_port(ct, repl, + ntohs(nla_get_u16(tb[CTA_PROTO_SRC_PORT]))); + if (tb[CTA_PROTO_DST_PORT]) + nfnl_ct_set_dst_port(ct, repl, + ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT]))); + if (tb[CTA_PROTO_ICMP_ID]) + nfnl_ct_set_icmp_id(ct, repl, + ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID]))); + if (tb[CTA_PROTO_ICMP_TYPE]) + nfnl_ct_set_icmp_type(ct, repl, + nla_get_u8(tb[CTA_PROTO_ICMP_TYPE])); + if (tb[CTA_PROTO_ICMP_CODE]) + nfnl_ct_set_icmp_code(ct, repl, + nla_get_u8(tb[CTA_PROTO_ICMP_CODE])); + + return 0; +} + +static int ct_parse_tuple(struct nfnl_ct *ct, int repl, struct nlattr *attr) +{ + struct nlattr *tb[CTA_TUPLE_MAX+1]; + int err; + + err = nla_parse_nested(tb, CTA_TUPLE_MAX, attr, ct_tuple_policy); + if (err < 0) + return err; + + if (tb[CTA_TUPLE_IP]) { + err = ct_parse_ip(ct, repl, tb[CTA_TUPLE_IP]); + if (err < 0) + return err; + } + + if (tb[CTA_TUPLE_PROTO]) { + err = ct_parse_proto(ct, repl, tb[CTA_TUPLE_PROTO]); + if (err < 0) + return err; + } + + return 0; +} + +static int ct_parse_protoinfo_tcp(struct nfnl_ct *ct, struct nlattr *attr) +{ + struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1]; + int err; + + err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr, + ct_protoinfo_tcp_policy); + if (err < 0) + return err; + + if (tb[CTA_PROTOINFO_TCP_STATE]) + nfnl_ct_set_tcp_state(ct, + nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE])); + + return 0; +} + +static int ct_parse_protoinfo(struct nfnl_ct *ct, struct nlattr *attr) +{ + struct nlattr *tb[CTA_PROTOINFO_MAX+1]; + int err; + + err = nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, + ct_protoinfo_policy); + if (err < 0) + return err; + + if (tb[CTA_PROTOINFO_TCP]) { + err = ct_parse_protoinfo_tcp(ct, tb[CTA_PROTOINFO_TCP]); + if (err < 0) + return err; + } + + return 0; +} + +static int ct_parse_counters(struct nfnl_ct *ct, int repl, struct nlattr *attr) +{ + struct nlattr *tb[CTA_COUNTERS_MAX+1]; + int err; + + err = nla_parse_nested(tb, CTA_COUNTERS_MAX, attr, ct_counters_policy); + if (err < 0) + return err; + + if (tb[CTA_COUNTERS_PACKETS]) + nfnl_ct_set_packets(ct, repl, + ntohll(nla_get_u64(tb[CTA_COUNTERS_PACKETS]))); + if (tb[CTA_COUNTERS32_PACKETS]) + nfnl_ct_set_packets(ct, repl, + ntohl(nla_get_u32(tb[CTA_COUNTERS32_PACKETS]))); + if (tb[CTA_COUNTERS_BYTES]) + nfnl_ct_set_bytes(ct, repl, + ntohll(nla_get_u64(tb[CTA_COUNTERS_BYTES]))); + if (tb[CTA_COUNTERS32_BYTES]) + nfnl_ct_set_bytes(ct, repl, + ntohl(nla_get_u32(tb[CTA_COUNTERS32_BYTES]))); + + return 0; +} + +int nfnlmsg_ct_group(struct nlmsghdr *nlh) +{ + switch (nfnlmsg_subtype(nlh)) { + case IPCTNL_MSG_CT_NEW: + if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL)) + return NFNLGRP_CONNTRACK_NEW; + else + return NFNLGRP_CONNTRACK_UPDATE; + case IPCTNL_MSG_CT_DELETE: + return NFNLGRP_CONNTRACK_DESTROY; + default: + return NFNLGRP_NONE; + } +} + +int nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result) +{ + struct nfnl_ct *ct; + struct nlattr *tb[CTA_MAX+1]; + int err; + + ct = nfnl_ct_alloc(); + if (!ct) + return -NLE_NOMEM; + + ct->ce_msgtype = nlh->nlmsg_type; + + err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX, + ct_policy); + if (err < 0) + goto errout; + + nfnl_ct_set_family(ct, nfnlmsg_family(nlh)); + + if (tb[CTA_TUPLE_ORIG]) { + err = ct_parse_tuple(ct, 0, tb[CTA_TUPLE_ORIG]); + if (err < 0) + goto errout; + } + if (tb[CTA_TUPLE_REPLY]) { + err = ct_parse_tuple(ct, 1, tb[CTA_TUPLE_REPLY]); + if (err < 0) + goto errout; + } + + if (tb[CTA_PROTOINFO]) { + err = ct_parse_protoinfo(ct, tb[CTA_PROTOINFO]); + if (err < 0) + goto errout; + } + + if (tb[CTA_STATUS]) + nfnl_ct_set_status(ct, ntohl(nla_get_u32(tb[CTA_STATUS]))); + if (tb[CTA_TIMEOUT]) + nfnl_ct_set_timeout(ct, ntohl(nla_get_u32(tb[CTA_TIMEOUT]))); + if (tb[CTA_MARK]) + nfnl_ct_set_mark(ct, ntohl(nla_get_u32(tb[CTA_MARK]))); + if (tb[CTA_USE]) + nfnl_ct_set_use(ct, ntohl(nla_get_u32(tb[CTA_USE]))); + if (tb[CTA_ID]) + nfnl_ct_set_id(ct, ntohl(nla_get_u32(tb[CTA_ID]))); + + if (tb[CTA_COUNTERS_ORIG]) { + err = ct_parse_counters(ct, 0, tb[CTA_COUNTERS_ORIG]); + if (err < 0) + goto errout; + } + + if (tb[CTA_COUNTERS_REPLY]) { + err = ct_parse_counters(ct, 1, tb[CTA_COUNTERS_REPLY]); + if (err < 0) + goto errout; + } + + *result = ct; + return 0; + +errout: + nfnl_ct_put(ct); + return err; +} + +static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *nlh, struct nl_parser_param *pp) +{ + struct nfnl_ct *ct; + int err; + + if ((err = nfnlmsg_ct_parse(nlh, &ct)) < 0) + goto errout; + + err = pp->pp_cb((struct nl_object *) ct, pp); +errout: + nfnl_ct_put(ct); + return err; +} + +int nfnl_ct_dump_request(struct nl_sock *sk) +{ + return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET, + NLM_F_DUMP, AF_UNSPEC, 0); +} + +static int ct_request_update(struct nl_cache *cache, struct nl_sock *sk) +{ + return nfnl_ct_dump_request(sk); +} + +static int nfnl_ct_build_tuple(struct nl_msg *msg, const struct nfnl_ct *ct, + int repl) +{ + struct nlattr *tuple, *ip, *proto; + struct nl_addr *addr; + int family; + + family = nfnl_ct_get_family(ct); + + tuple = nla_nest_start(msg, repl ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG); + if (!tuple) + goto nla_put_failure; + + ip = nla_nest_start(msg, CTA_TUPLE_IP); + if (!ip) + goto nla_put_failure; + + addr = nfnl_ct_get_src(ct, repl); + if (addr) + NLA_PUT_ADDR(msg, + family == AF_INET ? CTA_IP_V4_SRC : CTA_IP_V6_SRC, + addr); + + addr = nfnl_ct_get_dst(ct, repl); + if (addr) + NLA_PUT_ADDR(msg, + family == AF_INET ? CTA_IP_V4_DST : CTA_IP_V6_DST, + addr); + + nla_nest_end(msg, ip); + + proto = nla_nest_start(msg, CTA_TUPLE_PROTO); + if (!proto) + goto nla_put_failure; + + if (nfnl_ct_test_proto(ct)) + NLA_PUT_U8(msg, CTA_PROTO_NUM, nfnl_ct_get_proto(ct)); + + if (nfnl_ct_test_src_port(ct, repl)) + NLA_PUT_U16(msg, CTA_PROTO_SRC_PORT, + htons(nfnl_ct_get_src_port(ct, repl))); + + if (nfnl_ct_test_dst_port(ct, repl)) + NLA_PUT_U16(msg, CTA_PROTO_DST_PORT, + htons(nfnl_ct_get_dst_port(ct, repl))); + + if (nfnl_ct_test_icmp_id(ct, repl)) + NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID, + htons(nfnl_ct_get_icmp_id(ct, repl))); + + if (nfnl_ct_test_icmp_type(ct, repl)) + NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE, + nfnl_ct_get_icmp_type(ct, repl)); + + if (nfnl_ct_test_icmp_code(ct, repl)) + NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE, + nfnl_ct_get_icmp_code(ct, repl)); + + nla_nest_end(msg, proto); + + nla_nest_end(msg, tuple); + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +static int nfnl_ct_build_message(const struct nfnl_ct *ct, int cmd, int flags, + struct nl_msg **result) +{ + struct nl_msg *msg; + int err; + + msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_CTNETLINK, cmd, flags, + nfnl_ct_get_family(ct), 0); + if (msg == NULL) + return -NLE_NOMEM; + + if ((err = nfnl_ct_build_tuple(msg, ct, 0)) < 0) + goto err_out; + + *result = msg; + return 0; + +err_out: + nlmsg_free(msg); + return err; +} + +int nfnl_ct_build_add_request(const struct nfnl_ct *ct, int flags, + struct nl_msg **result) +{ + return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_NEW, flags, result); +} + +int nfnl_ct_add(struct nl_sock *sk, const struct nfnl_ct *ct, int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_ct_build_add_request(ct, flags, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +int nfnl_ct_build_delete_request(const struct nfnl_ct *ct, int flags, + struct nl_msg **result) +{ + return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_DELETE, flags, result); +} + +int nfnl_ct_del(struct nl_sock *sk, const struct nfnl_ct *ct, int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_ct_build_delete_request(ct, flags, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +int nfnl_ct_build_query_request(const struct nfnl_ct *ct, int flags, + struct nl_msg **result) +{ + return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_GET, flags, result); +} + +int nfnl_ct_query(struct nl_sock *sk, const struct nfnl_ct *ct, int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_ct_build_query_request(ct, flags, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +/** + * @name Cache Management + * @{ + */ + +/** + * Build a conntrack cache holding all conntrack currently in the kernel + * @arg sk Netlink socket. + * @arg result Pointer to store resulting cache. + * + * Allocates a new cache, initializes it properly and updates it to + * contain all conntracks currently in the kernel. + * + * @return 0 on success or a negative error code. + */ +int nfnl_ct_alloc_cache(struct nl_sock *sk, struct nl_cache **result) +{ + return nl_cache_alloc_and_fill(&nfnl_ct_ops, sk, result); +} + +/** @} */ + +/** + * @name Conntrack Addition + * @{ + */ + +/** @} */ + +static struct nl_af_group ct_groups[] = { + { AF_UNSPEC, NFNLGRP_CONNTRACK_NEW }, + { AF_UNSPEC, NFNLGRP_CONNTRACK_UPDATE }, + { AF_UNSPEC, NFNLGRP_CONNTRACK_DESTROY }, + { END_OF_GROUP_LIST }, +}; + +#define NFNLMSG_CT_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK, (type)) +static struct nl_cache_ops nfnl_ct_ops = { + .co_name = "netfilter/ct", + .co_hdrsize = NFNL_HDRLEN, + .co_msgtypes = { + { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_NEW), NL_ACT_NEW, "new" }, + { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_GET), NL_ACT_GET, "get" }, + { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_DELETE), NL_ACT_DEL, "del" }, + END_OF_MSGTYPES_LIST, + }, + .co_protocol = NETLINK_NETFILTER, + .co_groups = ct_groups, + .co_request_update = ct_request_update, + .co_msg_parser = ct_msg_parser, + .co_obj_ops = &ct_obj_ops, +}; + +static void __init ct_init(void) +{ + nl_cache_mngt_register(&nfnl_ct_ops); +} + +static void __exit ct_exit(void) +{ + nl_cache_mngt_unregister(&nfnl_ct_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/netfilter/ct_obj.c b/libnetwork/libnl3/lib/netfilter/ct_obj.c new file mode 100644 index 0000000..c205427 --- /dev/null +++ b/libnetwork/libnl3/lib/netfilter/ct_obj.c @@ -0,0 +1,785 @@ +/* + * lib/netfilter/ct_obj.c Conntrack Object + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + * Copyright (c) 2007 Philip Craig + * Copyright (c) 2007 Secure Computing Corporation + */ + +#include +#include +#include +#include + +#include +#include +#include + +/** @cond SKIP */ +#define CT_ATTR_FAMILY (1UL << 0) +#define CT_ATTR_PROTO (1UL << 1) + +#define CT_ATTR_TCP_STATE (1UL << 2) + +#define CT_ATTR_STATUS (1UL << 3) +#define CT_ATTR_TIMEOUT (1UL << 4) +#define CT_ATTR_MARK (1UL << 5) +#define CT_ATTR_USE (1UL << 6) +#define CT_ATTR_ID (1UL << 7) + +#define CT_ATTR_ORIG_SRC (1UL << 8) +#define CT_ATTR_ORIG_DST (1UL << 9) +#define CT_ATTR_ORIG_SRC_PORT (1UL << 10) +#define CT_ATTR_ORIG_DST_PORT (1UL << 11) +#define CT_ATTR_ORIG_ICMP_ID (1UL << 12) +#define CT_ATTR_ORIG_ICMP_TYPE (1UL << 13) +#define CT_ATTR_ORIG_ICMP_CODE (1UL << 14) +#define CT_ATTR_ORIG_PACKETS (1UL << 15) +#define CT_ATTR_ORIG_BYTES (1UL << 16) + +#define CT_ATTR_REPL_SRC (1UL << 17) +#define CT_ATTR_REPL_DST (1UL << 18) +#define CT_ATTR_REPL_SRC_PORT (1UL << 19) +#define CT_ATTR_REPL_DST_PORT (1UL << 20) +#define CT_ATTR_REPL_ICMP_ID (1UL << 21) +#define CT_ATTR_REPL_ICMP_TYPE (1UL << 22) +#define CT_ATTR_REPL_ICMP_CODE (1UL << 23) +#define CT_ATTR_REPL_PACKETS (1UL << 24) +#define CT_ATTR_REPL_BYTES (1UL << 25) +/** @endcond */ + +static void ct_free_data(struct nl_object *c) +{ + struct nfnl_ct *ct = (struct nfnl_ct *) c; + + if (ct == NULL) + return; + + nl_addr_put(ct->ct_orig.src); + nl_addr_put(ct->ct_orig.dst); + nl_addr_put(ct->ct_repl.src); + nl_addr_put(ct->ct_repl.dst); +} + +static int ct_clone(struct nl_object *_dst, struct nl_object *_src) +{ + struct nfnl_ct *dst = (struct nfnl_ct *) _dst; + struct nfnl_ct *src = (struct nfnl_ct *) _src; + struct nl_addr *addr; + + if (src->ct_orig.src) { + addr = nl_addr_clone(src->ct_orig.src); + if (!addr) + return -NLE_NOMEM; + dst->ct_orig.src = addr; + } + + if (src->ct_orig.dst) { + addr = nl_addr_clone(src->ct_orig.dst); + if (!addr) + return -NLE_NOMEM; + dst->ct_orig.dst = addr; + } + + if (src->ct_repl.src) { + addr = nl_addr_clone(src->ct_repl.src); + if (!addr) + return -NLE_NOMEM; + dst->ct_repl.src = addr; + } + + if (src->ct_repl.dst) { + addr = nl_addr_clone(src->ct_repl.dst); + if (!addr) + return -NLE_NOMEM; + dst->ct_repl.dst = addr; + } + + return 0; +} + +static void dump_addr(struct nl_dump_params *p, struct nl_addr *addr, int port) +{ + char buf[64]; + + if (addr) + nl_dump(p, "%s", nl_addr2str(addr, buf, sizeof(buf))); + + if (port) + nl_dump(p, ":%u ", port); + else if (addr) + nl_dump(p, " "); +} + +static void dump_icmp(struct nl_dump_params *p, struct nfnl_ct *ct, int reply) +{ + if (nfnl_ct_test_icmp_type(ct, reply)) + nl_dump(p, "icmp type %d ", nfnl_ct_get_icmp_type(ct, reply)); + + if (nfnl_ct_test_icmp_type(ct, reply)) + nl_dump(p, "code %d ", nfnl_ct_get_icmp_code(ct, reply)); + + if (nfnl_ct_test_icmp_type(ct, reply)) + nl_dump(p, "id %d ", nfnl_ct_get_icmp_id(ct, reply)); +} + +static void ct_dump_tuples(struct nfnl_ct *ct, struct nl_dump_params *p) +{ + struct nl_addr *orig_src, *orig_dst, *reply_src, *reply_dst; + int orig_sport = 0, orig_dport = 0, reply_sport = 0, reply_dport = 0; + int sync = 0; + + orig_src = nfnl_ct_get_src(ct, 0); + orig_dst = nfnl_ct_get_dst(ct, 0); + reply_src = nfnl_ct_get_src(ct, 1); + reply_dst = nfnl_ct_get_dst(ct, 1); + + if (nfnl_ct_test_src_port(ct, 0)) + orig_sport = nfnl_ct_get_src_port(ct, 0); + + if (nfnl_ct_test_dst_port(ct, 0)) + orig_dport = nfnl_ct_get_dst_port(ct, 0); + + if (nfnl_ct_test_src_port(ct, 1)) + reply_sport = nfnl_ct_get_src_port(ct, 1); + + if (nfnl_ct_test_dst_port(ct, 1)) + reply_dport = nfnl_ct_get_dst_port(ct, 1); + + if (orig_src && orig_dst && reply_src && reply_dst && + orig_sport == reply_dport && orig_dport == reply_sport && + !nl_addr_cmp(orig_src, reply_dst) && + !nl_addr_cmp(orig_dst, reply_src)) + sync = 1; + + dump_addr(p, orig_src, orig_sport); + nl_dump(p, sync ? "<-> " : "-> "); + dump_addr(p, orig_dst, orig_dport); + dump_icmp(p, ct, 0); + + if (!sync) { + dump_addr(p, reply_src, reply_sport); + nl_dump(p, "<- "); + dump_addr(p, reply_dst, reply_dport); + dump_icmp(p, ct, 1); + } +} + +/* Compatible with /proc/net/nf_conntrack */ +static void ct_dump_line(struct nl_object *a, struct nl_dump_params *p) +{ + struct nfnl_ct *ct = (struct nfnl_ct *) a; + char buf[64]; + + nl_new_line(p); + + if (nfnl_ct_test_proto(ct)) + nl_dump(p, "%s ", + nl_ip_proto2str(nfnl_ct_get_proto(ct), buf, sizeof(buf))); + + if (nfnl_ct_test_tcp_state(ct)) + nl_dump(p, "%s ", + nfnl_ct_tcp_state2str(nfnl_ct_get_tcp_state(ct), + buf, sizeof(buf))); + + ct_dump_tuples(ct, p); + + if (nfnl_ct_test_mark(ct) && nfnl_ct_get_mark(ct)) + nl_dump(p, "mark %u ", nfnl_ct_get_mark(ct)); + + nl_dump(p, "\n"); +} + +static void ct_dump_details(struct nl_object *a, struct nl_dump_params *p) +{ + struct nfnl_ct *ct = (struct nfnl_ct *) a; + char buf[64]; + int fp = 0; + + ct_dump_line(a, p); + + nl_dump(p, " id 0x%x ", ct->ct_id); + nl_dump_line(p, "family %s ", + nl_af2str(ct->ct_family, buf, sizeof(buf))); + + if (nfnl_ct_test_use(ct)) + nl_dump(p, "refcnt %u ", nfnl_ct_get_use(ct)); + + if (nfnl_ct_test_timeout(ct)) { + uint64_t timeout_ms = nfnl_ct_get_timeout(ct) * 1000UL; + nl_dump(p, "timeout %s ", + nl_msec2str(timeout_ms, buf, sizeof(buf))); + } + + if (ct->ct_status) + nl_dump(p, "<"); + +#define PRINT_FLAG(str) \ + { nl_dump(p, "%s%s", fp++ ? "," : "", (str)); } + + if (ct->ct_status & IPS_EXPECTED) + PRINT_FLAG("EXPECTED"); + if (!(ct->ct_status & IPS_SEEN_REPLY)) + PRINT_FLAG("NOREPLY"); + if (ct->ct_status & IPS_ASSURED) + PRINT_FLAG("ASSURED"); + if (!(ct->ct_status & IPS_CONFIRMED)) + PRINT_FLAG("NOTSENT"); + if (ct->ct_status & IPS_SRC_NAT) + PRINT_FLAG("SNAT"); + if (ct->ct_status & IPS_DST_NAT) + PRINT_FLAG("DNAT"); + if (ct->ct_status & IPS_SEQ_ADJUST) + PRINT_FLAG("SEQADJUST"); + if (!(ct->ct_status & IPS_SRC_NAT_DONE)) + PRINT_FLAG("SNAT_INIT"); + if (!(ct->ct_status & IPS_DST_NAT_DONE)) + PRINT_FLAG("DNAT_INIT"); + if (ct->ct_status & IPS_DYING) + PRINT_FLAG("DYING"); + if (ct->ct_status & IPS_FIXED_TIMEOUT) + PRINT_FLAG("FIXED_TIMEOUT"); +#undef PRINT_FLAG + + if (ct->ct_status) + nl_dump(p, ">"); + nl_dump(p, "\n"); +} + +static void ct_dump_stats(struct nl_object *a, struct nl_dump_params *p) +{ + struct nfnl_ct *ct = (struct nfnl_ct *) a; + double res; + char *unit; + + ct_dump_details(a, p); + + nl_dump_line(p, " # packets volume\n"); + + res = nl_cancel_down_bytes(nfnl_ct_get_bytes(ct, 1), &unit); + nl_dump_line(p, " rx %10llu %7.2f %s\n", + nfnl_ct_get_packets(ct, 1), res, unit); + + res = nl_cancel_down_bytes(nfnl_ct_get_bytes(ct, 0), &unit); + nl_dump_line(p, " tx %10llu %7.2f %s\n", + nfnl_ct_get_packets(ct, 0), res, unit); +} + +static int ct_compare(struct nl_object *_a, struct nl_object *_b, + uint32_t attrs, int flags) +{ + struct nfnl_ct *a = (struct nfnl_ct *) _a; + struct nfnl_ct *b = (struct nfnl_ct *) _b; + int diff = 0; + +#define CT_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, CT_ATTR_##ATTR, a, b, EXPR) +#define CT_DIFF_VAL(ATTR, FIELD) CT_DIFF(ATTR, a->FIELD != b->FIELD) +#define CT_DIFF_ADDR(ATTR, FIELD) \ + ((flags & LOOSE_COMPARISON) \ + ? CT_DIFF(ATTR, nl_addr_cmp_prefix(a->FIELD, b->FIELD)) \ + : CT_DIFF(ATTR, nl_addr_cmp(a->FIELD, b->FIELD))) + + diff |= CT_DIFF_VAL(FAMILY, ct_family); + diff |= CT_DIFF_VAL(PROTO, ct_proto); + diff |= CT_DIFF_VAL(TCP_STATE, ct_protoinfo.tcp.state); + diff |= CT_DIFF_VAL(TIMEOUT, ct_timeout); + diff |= CT_DIFF_VAL(MARK, ct_mark); + diff |= CT_DIFF_VAL(USE, ct_use); + diff |= CT_DIFF_VAL(ID, ct_id); + diff |= CT_DIFF_ADDR(ORIG_SRC, ct_orig.src); + diff |= CT_DIFF_ADDR(ORIG_DST, ct_orig.dst); + diff |= CT_DIFF_VAL(ORIG_SRC_PORT, ct_orig.proto.port.src); + diff |= CT_DIFF_VAL(ORIG_DST_PORT, ct_orig.proto.port.dst); + diff |= CT_DIFF_VAL(ORIG_ICMP_ID, ct_orig.proto.icmp.id); + diff |= CT_DIFF_VAL(ORIG_ICMP_TYPE, ct_orig.proto.icmp.type); + diff |= CT_DIFF_VAL(ORIG_ICMP_CODE, ct_orig.proto.icmp.code); + diff |= CT_DIFF_VAL(ORIG_PACKETS, ct_orig.packets); + diff |= CT_DIFF_VAL(ORIG_BYTES, ct_orig.bytes); + diff |= CT_DIFF_ADDR(REPL_SRC, ct_repl.src); + diff |= CT_DIFF_ADDR(REPL_DST, ct_repl.dst); + diff |= CT_DIFF_VAL(REPL_SRC_PORT, ct_repl.proto.port.src); + diff |= CT_DIFF_VAL(REPL_DST_PORT, ct_repl.proto.port.dst); + diff |= CT_DIFF_VAL(REPL_ICMP_ID, ct_repl.proto.icmp.id); + diff |= CT_DIFF_VAL(REPL_ICMP_TYPE, ct_repl.proto.icmp.type); + diff |= CT_DIFF_VAL(REPL_ICMP_CODE, ct_repl.proto.icmp.code); + diff |= CT_DIFF_VAL(REPL_PACKETS, ct_repl.packets); + diff |= CT_DIFF_VAL(REPL_BYTES, ct_repl.bytes); + + if (flags & LOOSE_COMPARISON) + diff |= CT_DIFF(STATUS, (a->ct_status ^ b->ct_status) & + b->ct_status_mask); + else + diff |= CT_DIFF(STATUS, a->ct_status != b->ct_status); + +#undef CT_DIFF +#undef CT_DIFF_VAL +#undef CT_DIFF_ADDR + + return diff; +} + +static const struct trans_tbl ct_attrs[] = { + __ADD(CT_ATTR_FAMILY, family) + __ADD(CT_ATTR_PROTO, proto) + __ADD(CT_ATTR_TCP_STATE, tcpstate) + __ADD(CT_ATTR_STATUS, status) + __ADD(CT_ATTR_TIMEOUT, timeout) + __ADD(CT_ATTR_MARK, mark) + __ADD(CT_ATTR_USE, use) + __ADD(CT_ATTR_ID, id) + __ADD(CT_ATTR_ORIG_SRC, origsrc) + __ADD(CT_ATTR_ORIG_DST, origdst) + __ADD(CT_ATTR_ORIG_SRC_PORT, origsrcport) + __ADD(CT_ATTR_ORIG_DST_PORT, origdstport) + __ADD(CT_ATTR_ORIG_ICMP_ID, origicmpid) + __ADD(CT_ATTR_ORIG_ICMP_TYPE, origicmptype) + __ADD(CT_ATTR_ORIG_ICMP_CODE, origicmpcode) + __ADD(CT_ATTR_ORIG_PACKETS, origpackets) + __ADD(CT_ATTR_ORIG_BYTES, origbytes) + __ADD(CT_ATTR_REPL_SRC, replysrc) + __ADD(CT_ATTR_REPL_DST, replydst) + __ADD(CT_ATTR_REPL_SRC_PORT, replysrcport) + __ADD(CT_ATTR_REPL_DST_PORT, replydstport) + __ADD(CT_ATTR_REPL_ICMP_ID, replyicmpid) + __ADD(CT_ATTR_REPL_ICMP_TYPE, replyicmptype) + __ADD(CT_ATTR_REPL_ICMP_CODE, replyicmpcode) + __ADD(CT_ATTR_REPL_PACKETS, replypackets) + __ADD(CT_ATTR_REPL_BYTES, replybytes) +}; + +static char *ct_attrs2str(int attrs, char *buf, size_t len) +{ + return __flags2str(attrs, buf, len, ct_attrs, ARRAY_SIZE(ct_attrs)); +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct nfnl_ct *nfnl_ct_alloc(void) +{ + return (struct nfnl_ct *) nl_object_alloc(&ct_obj_ops); +} + +void nfnl_ct_get(struct nfnl_ct *ct) +{ + nl_object_get((struct nl_object *) ct); +} + +void nfnl_ct_put(struct nfnl_ct *ct) +{ + nl_object_put((struct nl_object *) ct); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void nfnl_ct_set_family(struct nfnl_ct *ct, uint8_t family) +{ + ct->ct_family = family; + ct->ce_mask |= CT_ATTR_FAMILY; +} + +uint8_t nfnl_ct_get_family(const struct nfnl_ct *ct) +{ + if (ct->ce_mask & CT_ATTR_FAMILY) + return ct->ct_family; + else + return AF_UNSPEC; +} + +void nfnl_ct_set_proto(struct nfnl_ct *ct, uint8_t proto) +{ + ct->ct_proto = proto; + ct->ce_mask |= CT_ATTR_PROTO; +} + +int nfnl_ct_test_proto(const struct nfnl_ct *ct) +{ + return !!(ct->ce_mask & CT_ATTR_PROTO); +} + +uint8_t nfnl_ct_get_proto(const struct nfnl_ct *ct) +{ + return ct->ct_proto; +} + +void nfnl_ct_set_tcp_state(struct nfnl_ct *ct, uint8_t state) +{ + ct->ct_protoinfo.tcp.state = state; + ct->ce_mask |= CT_ATTR_TCP_STATE; +} + +int nfnl_ct_test_tcp_state(const struct nfnl_ct *ct) +{ + return !!(ct->ce_mask & CT_ATTR_TCP_STATE); +} + +uint8_t nfnl_ct_get_tcp_state(const struct nfnl_ct *ct) +{ + return ct->ct_protoinfo.tcp.state; +} + +static const struct trans_tbl tcp_states[] = { + __ADD(TCP_CONNTRACK_NONE,NONE) + __ADD(TCP_CONNTRACK_SYN_SENT,SYN_SENT) + __ADD(TCP_CONNTRACK_SYN_RECV,SYN_RECV) + __ADD(TCP_CONNTRACK_ESTABLISHED,ESTABLISHED) + __ADD(TCP_CONNTRACK_FIN_WAIT,FIN_WAIT) + __ADD(TCP_CONNTRACK_CLOSE_WAIT,CLOSE_WAIT) + __ADD(TCP_CONNTRACK_LAST_ACK,LAST_ACK) + __ADD(TCP_CONNTRACK_TIME_WAIT,TIME_WAIT) + __ADD(TCP_CONNTRACK_CLOSE,CLOSE) + __ADD(TCP_CONNTRACK_LISTEN,LISTEN) +}; + +char *nfnl_ct_tcp_state2str(uint8_t state, char *buf, size_t len) +{ + return __type2str(state, buf, len, tcp_states, ARRAY_SIZE(tcp_states)); +} + +int nfnl_ct_str2tcp_state(const char *name) +{ + return __str2type(name, tcp_states, ARRAY_SIZE(tcp_states)); +} + +void nfnl_ct_set_status(struct nfnl_ct *ct, uint32_t status) +{ + ct->ct_status_mask |= status; + ct->ct_status |= status; + ct->ce_mask |= CT_ATTR_STATUS; +} + +void nfnl_ct_unset_status(struct nfnl_ct *ct, uint32_t status) +{ + ct->ct_status_mask |= status; + ct->ct_status &= ~status; + ct->ce_mask |= CT_ATTR_STATUS; +} + +uint32_t nfnl_ct_get_status(const struct nfnl_ct *ct) +{ + return ct->ct_status; +} + +static const struct trans_tbl status_flags[] = { + __ADD(IPS_EXPECTED, expected) + __ADD(IPS_SEEN_REPLY, seen_reply) + __ADD(IPS_ASSURED, assured) + __ADD(IPS_CONFIRMED, confirmed) + __ADD(IPS_SRC_NAT, snat) + __ADD(IPS_DST_NAT, dnat) + __ADD(IPS_SEQ_ADJUST, seqadjust) + __ADD(IPS_SRC_NAT_DONE, snat_done) + __ADD(IPS_DST_NAT_DONE, dnat_done) + __ADD(IPS_DYING, dying) + __ADD(IPS_FIXED_TIMEOUT, fixed_timeout) +}; + +char * nfnl_ct_status2str(int flags, char *buf, size_t len) +{ + return __flags2str(flags, buf, len, status_flags, + ARRAY_SIZE(status_flags)); +} + +int nfnl_ct_str2status(const char *name) +{ + return __str2flags(name, status_flags, ARRAY_SIZE(status_flags)); +} + +void nfnl_ct_set_timeout(struct nfnl_ct *ct, uint32_t timeout) +{ + ct->ct_timeout = timeout; + ct->ce_mask |= CT_ATTR_TIMEOUT; +} + +int nfnl_ct_test_timeout(const struct nfnl_ct *ct) +{ + return !!(ct->ce_mask & CT_ATTR_TIMEOUT); +} + +uint32_t nfnl_ct_get_timeout(const struct nfnl_ct *ct) +{ + return ct->ct_timeout; +} + +void nfnl_ct_set_mark(struct nfnl_ct *ct, uint32_t mark) +{ + ct->ct_mark = mark; + ct->ce_mask |= CT_ATTR_MARK; +} + +int nfnl_ct_test_mark(const struct nfnl_ct *ct) +{ + return !!(ct->ce_mask & CT_ATTR_MARK); +} + +uint32_t nfnl_ct_get_mark(const struct nfnl_ct *ct) +{ + return ct->ct_mark; +} + +void nfnl_ct_set_use(struct nfnl_ct *ct, uint32_t use) +{ + ct->ct_use = use; + ct->ce_mask |= CT_ATTR_USE; +} + +int nfnl_ct_test_use(const struct nfnl_ct *ct) +{ + return !!(ct->ce_mask & CT_ATTR_USE); +} + +uint32_t nfnl_ct_get_use(const struct nfnl_ct *ct) +{ + return ct->ct_use; +} + +void nfnl_ct_set_id(struct nfnl_ct *ct, uint32_t id) +{ + ct->ct_id = id; + ct->ce_mask |= CT_ATTR_ID; +} + +int nfnl_ct_test_id(const struct nfnl_ct *ct) +{ + return !!(ct->ce_mask & CT_ATTR_ID); +} + +uint32_t nfnl_ct_get_id(const struct nfnl_ct *ct) +{ + return ct->ct_id; +} + +static int ct_set_addr(struct nfnl_ct *ct, struct nl_addr *addr, + int attr, struct nl_addr ** ct_addr) +{ + if (ct->ce_mask & CT_ATTR_FAMILY) { + if (addr->a_family != ct->ct_family) + return -NLE_AF_MISMATCH; + } else + nfnl_ct_set_family(ct, addr->a_family); + + if (*ct_addr) + nl_addr_put(*ct_addr); + + nl_addr_get(addr); + *ct_addr = addr; + ct->ce_mask |= attr; + + return 0; +} + +int nfnl_ct_set_src(struct nfnl_ct *ct, int repl, struct nl_addr *addr) +{ + struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + int attr = repl ? CT_ATTR_REPL_SRC : CT_ATTR_ORIG_SRC; + return ct_set_addr(ct, addr, attr, &dir->src); +} + +int nfnl_ct_set_dst(struct nfnl_ct *ct, int repl, struct nl_addr *addr) +{ + struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + int attr = repl ? CT_ATTR_REPL_DST : CT_ATTR_ORIG_DST; + return ct_set_addr(ct, addr, attr, &dir->dst); +} + +struct nl_addr *nfnl_ct_get_src(const struct nfnl_ct *ct, int repl) +{ + const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + int attr = repl ? CT_ATTR_REPL_SRC : CT_ATTR_ORIG_SRC; + if (!(ct->ce_mask & attr)) + return NULL; + return dir->src; +} + +struct nl_addr *nfnl_ct_get_dst(const struct nfnl_ct *ct, int repl) +{ + const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + int attr = repl ? CT_ATTR_REPL_DST : CT_ATTR_ORIG_DST; + if (!(ct->ce_mask & attr)) + return NULL; + return dir->dst; +} + +void nfnl_ct_set_src_port(struct nfnl_ct *ct, int repl, uint16_t port) +{ + struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + int attr = repl ? CT_ATTR_REPL_SRC_PORT : CT_ATTR_ORIG_SRC_PORT; + + dir->proto.port.src = port; + ct->ce_mask |= attr; +} + +int nfnl_ct_test_src_port(const struct nfnl_ct *ct, int repl) +{ + int attr = repl ? CT_ATTR_REPL_SRC_PORT : CT_ATTR_ORIG_SRC_PORT; + return !!(ct->ce_mask & attr); +} + +uint16_t nfnl_ct_get_src_port(const struct nfnl_ct *ct, int repl) +{ + const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + + return dir->proto.port.src; +} + +void nfnl_ct_set_dst_port(struct nfnl_ct *ct, int repl, uint16_t port) +{ + struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + int attr = repl ? CT_ATTR_REPL_DST_PORT : CT_ATTR_ORIG_DST_PORT; + + dir->proto.port.dst = port; + ct->ce_mask |= attr; +} + +int nfnl_ct_test_dst_port(const struct nfnl_ct *ct, int repl) +{ + int attr = repl ? CT_ATTR_REPL_DST_PORT : CT_ATTR_ORIG_DST_PORT; + return !!(ct->ce_mask & attr); +} + +uint16_t nfnl_ct_get_dst_port(const struct nfnl_ct *ct, int repl) +{ + const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + + return dir->proto.port.dst; +} + +void nfnl_ct_set_icmp_id(struct nfnl_ct *ct, int repl, uint16_t id) +{ + struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + int attr = repl ? CT_ATTR_REPL_ICMP_ID : CT_ATTR_ORIG_ICMP_ID; + + dir->proto.icmp.id = id; + ct->ce_mask |= attr; +} + +int nfnl_ct_test_icmp_id(const struct nfnl_ct *ct, int repl) +{ + int attr = repl ? CT_ATTR_REPL_ICMP_ID : CT_ATTR_ORIG_ICMP_ID; + return !!(ct->ce_mask & attr); +} + +uint16_t nfnl_ct_get_icmp_id(const struct nfnl_ct *ct, int repl) +{ + const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + + return dir->proto.icmp.id; +} + +void nfnl_ct_set_icmp_type(struct nfnl_ct *ct, int repl, uint8_t type) +{ + struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + int attr = repl ? CT_ATTR_REPL_ICMP_TYPE : CT_ATTR_ORIG_ICMP_TYPE; + + dir->proto.icmp.type = type; + ct->ce_mask |= attr; +} + +int nfnl_ct_test_icmp_type(const struct nfnl_ct *ct, int repl) +{ + int attr = repl ? CT_ATTR_REPL_ICMP_TYPE : CT_ATTR_ORIG_ICMP_TYPE; + return !!(ct->ce_mask & attr); +} + +uint8_t nfnl_ct_get_icmp_type(const struct nfnl_ct *ct, int repl) +{ + const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + + return dir->proto.icmp.type; +} + +void nfnl_ct_set_icmp_code(struct nfnl_ct *ct, int repl, uint8_t code) +{ + struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + int attr = repl ? CT_ATTR_REPL_ICMP_CODE : CT_ATTR_ORIG_ICMP_CODE; + + dir->proto.icmp.code = code; + ct->ce_mask |= attr; +} + +int nfnl_ct_test_icmp_code(const struct nfnl_ct *ct, int repl) +{ + int attr = repl ? CT_ATTR_REPL_ICMP_CODE : CT_ATTR_ORIG_ICMP_CODE; + return !!(ct->ce_mask & attr); +} + +uint8_t nfnl_ct_get_icmp_code(const struct nfnl_ct *ct, int repl) +{ + const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + + return dir->proto.icmp.code; +} + +void nfnl_ct_set_packets(struct nfnl_ct *ct, int repl, uint64_t packets) +{ + struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + int attr = repl ? CT_ATTR_REPL_PACKETS : CT_ATTR_ORIG_PACKETS; + + dir->packets = packets; + ct->ce_mask |= attr; +} + +int nfnl_ct_test_packets(const struct nfnl_ct *ct, int repl) +{ + int attr = repl ? CT_ATTR_REPL_PACKETS : CT_ATTR_ORIG_PACKETS; + return !!(ct->ce_mask & attr); +} + +uint64_t nfnl_ct_get_packets(const struct nfnl_ct *ct, int repl) +{ + const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + + return dir->packets; +} + +void nfnl_ct_set_bytes(struct nfnl_ct *ct, int repl, uint64_t bytes) +{ + struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + int attr = repl ? CT_ATTR_REPL_BYTES : CT_ATTR_ORIG_BYTES; + + dir->bytes = bytes; + ct->ce_mask |= attr; +} + +int nfnl_ct_test_bytes(const struct nfnl_ct *ct, int repl) +{ + int attr = repl ? CT_ATTR_REPL_BYTES : CT_ATTR_ORIG_BYTES; + return !!(ct->ce_mask & attr); +} + +uint64_t nfnl_ct_get_bytes(const struct nfnl_ct *ct, int repl) +{ + const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig; + + return dir->bytes; +} + +/** @} */ + +struct nl_object_ops ct_obj_ops = { + .oo_name = "netfilter/ct", + .oo_size = sizeof(struct nfnl_ct), + .oo_free_data = ct_free_data, + .oo_clone = ct_clone, + .oo_dump = { + [NL_DUMP_LINE] = ct_dump_line, + [NL_DUMP_DETAILS] = ct_dump_details, + [NL_DUMP_STATS] = ct_dump_stats, + }, + .oo_compare = ct_compare, + .oo_attrs2str = ct_attrs2str, +}; + +/** @} */ diff --git a/libnetwork/libnl3/lib/netfilter/log.c b/libnetwork/libnl3/lib/netfilter/log.c new file mode 100644 index 0000000..96ae6c5 --- /dev/null +++ b/libnetwork/libnl3/lib/netfilter/log.c @@ -0,0 +1,251 @@ +/* + * lib/netfilter/log.c Netfilter Log + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + * Copyright (c) 2007 Philip Craig + * Copyright (c) 2007 Secure Computing Corporation + */ + +/** + * @ingroup nfnl + * @defgroup log Log + * @brief + * @{ + */ + +#include +#include + +#include +#include +#include +#include + +/** + * @name Log Commands + * @{ + */ + +static int build_log_cmd_request(uint8_t family, uint16_t queuenum, + uint8_t command, struct nl_msg **result) +{ + struct nl_msg *msg; + struct nfulnl_msg_config_cmd cmd; + + msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_ULOG, NFULNL_MSG_CONFIG, 0, + family, queuenum); + if (msg == NULL) + return -NLE_NOMEM; + + cmd.command = command; + if (nla_put(msg, NFULA_CFG_CMD, sizeof(cmd), &cmd) < 0) + goto nla_put_failure; + + *result = msg; + return 0; + +nla_put_failure: + nlmsg_free(msg); + return -NLE_MSGSIZE; +} + +static int send_log_request(struct nl_sock *sk, struct nl_msg *msg) +{ + int err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +int nfnl_log_build_pf_bind(uint8_t pf, struct nl_msg **result) +{ + return build_log_cmd_request(pf, 0, NFULNL_CFG_CMD_PF_BIND, result); +} + +int nfnl_log_pf_bind(struct nl_sock *nlh, uint8_t pf) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_log_build_pf_bind(pf, &msg)) < 0) + return err; + + return send_log_request(nlh, msg); +} + +int nfnl_log_build_pf_unbind(uint8_t pf, struct nl_msg **result) +{ + return build_log_cmd_request(pf, 0, NFULNL_CFG_CMD_PF_UNBIND, result); +} + +int nfnl_log_pf_unbind(struct nl_sock *nlh, uint8_t pf) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_log_build_pf_unbind(pf, &msg)) < 0) + return err; + + return send_log_request(nlh, msg); +} + +static int nfnl_log_build_request(const struct nfnl_log *log, + struct nl_msg **result) +{ + struct nl_msg *msg; + + if (!nfnl_log_test_group(log)) + return -NLE_MISSING_ATTR; + + msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_ULOG, NFULNL_MSG_CONFIG, 0, + 0, nfnl_log_get_group(log)); + if (msg == NULL) + return -NLE_NOMEM; + + /* This sucks. The nfnetlink_log interface always expects both + * parameters to be present. Needs to be done properly. + */ + if (nfnl_log_test_copy_mode(log)) { + struct nfulnl_msg_config_mode mode; + + switch (nfnl_log_get_copy_mode(log)) { + case NFNL_LOG_COPY_NONE: + mode.copy_mode = NFULNL_COPY_NONE; + break; + case NFNL_LOG_COPY_META: + mode.copy_mode = NFULNL_COPY_META; + break; + case NFNL_LOG_COPY_PACKET: + mode.copy_mode = NFULNL_COPY_PACKET; + break; + } + mode.copy_range = htonl(nfnl_log_get_copy_range(log)); + mode._pad = 0; + + if (nla_put(msg, NFULA_CFG_MODE, sizeof(mode), &mode) < 0) + goto nla_put_failure; + } + + if (nfnl_log_test_flush_timeout(log) && + nla_put_u32(msg, NFULA_CFG_TIMEOUT, + htonl(nfnl_log_get_flush_timeout(log))) < 0) + goto nla_put_failure; + + if (nfnl_log_test_alloc_size(log) && + nla_put_u32(msg, NFULA_CFG_NLBUFSIZ, + htonl(nfnl_log_get_alloc_size(log))) < 0) + goto nla_put_failure; + + if (nfnl_log_test_queue_threshold(log) && + nla_put_u32(msg, NFULA_CFG_QTHRESH, + htonl(nfnl_log_get_queue_threshold(log))) < 0) + goto nla_put_failure; + + *result = msg; + return 0; + +nla_put_failure: + nlmsg_free(msg); + return -NLE_MSGSIZE; +} + +int nfnl_log_build_create_request(const struct nfnl_log *log, + struct nl_msg **result) +{ + struct nfulnl_msg_config_cmd cmd; + int err; + + if ((err = nfnl_log_build_request(log, result)) < 0) + return err; + + cmd.command = NFULNL_CFG_CMD_BIND; + + if (nla_put(*result, NFULA_CFG_CMD, sizeof(cmd), &cmd) < 0) + goto nla_put_failure; + + return 0; + +nla_put_failure: + nlmsg_free(*result); + return -NLE_MSGSIZE; +} + +int nfnl_log_create(struct nl_sock *nlh, const struct nfnl_log *log) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_log_build_create_request(log, &msg)) < 0) + return err; + + return send_log_request(nlh, msg); +} + +int nfnl_log_build_change_request(const struct nfnl_log *log, + struct nl_msg **result) +{ + return nfnl_log_build_request(log, result); +} + +int nfnl_log_change(struct nl_sock *nlh, const struct nfnl_log *log) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_log_build_change_request(log, &msg)) < 0) + return err; + + return send_log_request(nlh, msg); +} + +int nfnl_log_build_delete_request(const struct nfnl_log *log, + struct nl_msg **result) +{ + if (!nfnl_log_test_group(log)) + return -NLE_MISSING_ATTR; + + return build_log_cmd_request(0, nfnl_log_get_group(log), + NFULNL_CFG_CMD_UNBIND, result); +} + +int nfnl_log_delete(struct nl_sock *nlh, const struct nfnl_log *log) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_log_build_delete_request(log, &msg)) < 0) + return err; + + return send_log_request(nlh, msg); +} + +/** @} */ + +static struct nl_cache_ops nfnl_log_ops = { + .co_name = "netfilter/log", + .co_obj_ops = &log_obj_ops, + .co_msgtypes = { + END_OF_MSGTYPES_LIST, + }, +}; + +static void __init log_init(void) +{ + nl_cache_mngt_register(&nfnl_log_ops); +} + +static void __exit log_exit(void) +{ + nl_cache_mngt_unregister(&nfnl_log_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/netfilter/log_msg.c b/libnetwork/libnl3/lib/netfilter/log_msg.c new file mode 100644 index 0000000..cad6ddd --- /dev/null +++ b/libnetwork/libnl3/lib/netfilter/log_msg.c @@ -0,0 +1,209 @@ +/* + * lib/netfilter/log_msg.c Netfilter Log Message + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + * Copyright (c) 2007 Philip Craig + * Copyright (c) 2007 Secure Computing Corporation + * Copyright (c) 2008 Patrick McHardy + */ + +/** + * @ingroup nfnl + * @defgroup log Log + * @brief + * @{ + */ + +#include +#include + +#include +#include +#include +#include + +#if __BYTE_ORDER == __BIG_ENDIAN +static uint64_t ntohll(uint64_t x) +{ + return x; +} +#elif __BYTE_ORDER == __LITTLE_ENDIAN +static uint64_t ntohll(uint64_t x) +{ + return __bswap_64(x); +} +#endif + +static struct nla_policy log_msg_policy[NFULA_MAX+1] = { + [NFULA_PACKET_HDR] = { + .minlen = sizeof(struct nfulnl_msg_packet_hdr) + }, + [NFULA_MARK] = { .type = NLA_U32 }, + [NFULA_TIMESTAMP] = { + .minlen = sizeof(struct nfulnl_msg_packet_timestamp) + }, + [NFULA_IFINDEX_INDEV] = { .type = NLA_U32 }, + [NFULA_IFINDEX_OUTDEV] = { .type = NLA_U32 }, + [NFULA_IFINDEX_PHYSINDEV] = { .type = NLA_U32 }, + [NFULA_IFINDEX_PHYSOUTDEV] = { .type = NLA_U32 }, + [NFULA_HWADDR] = { + .minlen = sizeof(struct nfulnl_msg_packet_hw) + }, + //[NFULA_PAYLOAD] + [NFULA_PREFIX] = { .type = NLA_STRING, }, + [NFULA_UID] = { .type = NLA_U32 }, + [NFULA_GID] = { .type = NLA_U32 }, + [NFULA_SEQ] = { .type = NLA_U32 }, + [NFULA_SEQ_GLOBAL] = { .type = NLA_U32 }, +}; + +int nfnlmsg_log_msg_parse(struct nlmsghdr *nlh, struct nfnl_log_msg **result) +{ + struct nfnl_log_msg *msg; + struct nlattr *tb[NFULA_MAX+1]; + struct nlattr *attr; + int err; + + msg = nfnl_log_msg_alloc(); + if (!msg) + return -NLE_NOMEM; + + msg->ce_msgtype = nlh->nlmsg_type; + + err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, NFULA_MAX, + log_msg_policy); + if (err < 0) + goto errout; + + nfnl_log_msg_set_family(msg, nfnlmsg_family(nlh)); + + attr = tb[NFULA_PACKET_HDR]; + if (attr) { + struct nfulnl_msg_packet_hdr *hdr = nla_data(attr); + + if (hdr->hw_protocol) + nfnl_log_msg_set_hwproto(msg, hdr->hw_protocol); + nfnl_log_msg_set_hook(msg, hdr->hook); + } + + attr = tb[NFULA_MARK]; + if (attr) + nfnl_log_msg_set_mark(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFULA_TIMESTAMP]; + if (attr) { + struct nfulnl_msg_packet_timestamp *timestamp = nla_data(attr); + struct timeval tv; + + tv.tv_sec = ntohll(timestamp->sec); + tv.tv_usec = ntohll(timestamp->usec); + nfnl_log_msg_set_timestamp(msg, &tv); + } + + attr = tb[NFULA_IFINDEX_INDEV]; + if (attr) + nfnl_log_msg_set_indev(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFULA_IFINDEX_OUTDEV]; + if (attr) + nfnl_log_msg_set_outdev(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFULA_IFINDEX_PHYSINDEV]; + if (attr) + nfnl_log_msg_set_physindev(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFULA_IFINDEX_PHYSOUTDEV]; + if (attr) + nfnl_log_msg_set_physoutdev(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFULA_HWADDR]; + if (attr) { + struct nfulnl_msg_packet_hw *hw = nla_data(attr); + + nfnl_log_msg_set_hwaddr(msg, hw->hw_addr, ntohs(hw->hw_addrlen)); + } + + attr = tb[NFULA_PAYLOAD]; + if (attr) { + err = nfnl_log_msg_set_payload(msg, nla_data(attr), nla_len(attr)); + if (err < 0) + goto errout; + } + + attr = tb[NFULA_PREFIX]; + if (attr) { + err = nfnl_log_msg_set_prefix(msg, nla_data(attr)); + if (err < 0) + goto errout; + } + + attr = tb[NFULA_UID]; + if (attr) + nfnl_log_msg_set_uid(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFULA_GID]; + if (attr) + nfnl_log_msg_set_gid(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFULA_SEQ]; + if (attr) + nfnl_log_msg_set_seq(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFULA_SEQ_GLOBAL]; + if (attr) + nfnl_log_msg_set_seq_global(msg, ntohl(nla_get_u32(attr))); + + *result = msg; + return 0; + +errout: + nfnl_log_msg_put(msg); + return err; +} + +static int log_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *nlh, struct nl_parser_param *pp) +{ + struct nfnl_log_msg *msg; + int err; + + if ((err = nfnlmsg_log_msg_parse(nlh, &msg)) < 0) + goto errout; + + err = pp->pp_cb((struct nl_object *) msg, pp); +errout: + nfnl_log_msg_put(msg); + return err; +} + +/** @} */ + +#define NFNLMSG_LOG_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_ULOG, (type)) +static struct nl_cache_ops nfnl_log_msg_ops = { + .co_name = "netfilter/log_msg", + .co_hdrsize = NFNL_HDRLEN, + .co_msgtypes = { + { NFNLMSG_LOG_TYPE(NFULNL_MSG_PACKET), NL_ACT_NEW, "new" }, + END_OF_MSGTYPES_LIST, + }, + .co_protocol = NETLINK_NETFILTER, + .co_msg_parser = log_msg_parser, + .co_obj_ops = &log_msg_obj_ops, +}; + +static void __init log_msg_init(void) +{ + nl_cache_mngt_register(&nfnl_log_msg_ops); +} + +static void __exit log_msg_exit(void) +{ + nl_cache_mngt_unregister(&nfnl_log_msg_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/netfilter/log_msg_obj.c b/libnetwork/libnl3/lib/netfilter/log_msg_obj.c new file mode 100644 index 0000000..d2cde4e --- /dev/null +++ b/libnetwork/libnl3/lib/netfilter/log_msg_obj.c @@ -0,0 +1,458 @@ +/* + * lib/netfilter/log_msg_obj.c Netfilter Log Object + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + * Copyright (c) 2007 Philip Craig + * Copyright (c) 2007 Secure Computing Corporation + */ + +#include +#include +#include +#include + +/** @cond SKIP */ +#define LOG_MSG_ATTR_FAMILY (1UL << 0) +#define LOG_MSG_ATTR_HWPROTO (1UL << 1) +#define LOG_MSG_ATTR_HOOK (1UL << 2) +#define LOG_MSG_ATTR_MARK (1UL << 3) +#define LOG_MSG_ATTR_TIMESTAMP (1UL << 4) +#define LOG_MSG_ATTR_INDEV (1UL << 5) +#define LOG_MSG_ATTR_OUTDEV (1UL << 6) +#define LOG_MSG_ATTR_PHYSINDEV (1UL << 7) +#define LOG_MSG_ATTR_PHYSOUTDEV (1UL << 8) +#define LOG_MSG_ATTR_HWADDR (1UL << 9) +#define LOG_MSG_ATTR_PAYLOAD (1UL << 10) +#define LOG_MSG_ATTR_PREFIX (1UL << 11) +#define LOG_MSG_ATTR_UID (1UL << 12) +#define LOG_MSG_ATTR_GID (1UL << 13) +#define LOG_MSG_ATTR_SEQ (1UL << 14) +#define LOG_MSG_ATTR_SEQ_GLOBAL (1UL << 15) +/** @endcond */ + +static void log_msg_free_data(struct nl_object *c) +{ + struct nfnl_log_msg *msg = (struct nfnl_log_msg *) c; + + if (msg == NULL) + return; + + free(msg->log_msg_payload); + free(msg->log_msg_prefix); +} + +static int log_msg_clone(struct nl_object *_dst, struct nl_object *_src) +{ + struct nfnl_log_msg *dst = (struct nfnl_log_msg *) _dst; + struct nfnl_log_msg *src = (struct nfnl_log_msg *) _src; + int err; + + if (src->log_msg_payload) { + err = nfnl_log_msg_set_payload(dst, src->log_msg_payload, + src->log_msg_payload_len); + if (err < 0) + goto errout; + } + + if (src->log_msg_prefix) { + err = nfnl_log_msg_set_prefix(dst, src->log_msg_prefix); + if (err < 0) + goto errout; + } + + return 0; +errout: + return err; +} + +static void log_msg_dump(struct nl_object *a, struct nl_dump_params *p) +{ + struct nfnl_log_msg *msg = (struct nfnl_log_msg *) a; + struct nl_cache *link_cache; + char buf[64]; + + link_cache = nl_cache_mngt_require("route/link"); + + nl_new_line(p); + + if (msg->ce_mask & LOG_MSG_ATTR_PREFIX) + nl_dump(p, "%s", msg->log_msg_prefix); + + if (msg->ce_mask & LOG_MSG_ATTR_INDEV) { + if (link_cache) + nl_dump(p, "IN=%s ", + rtnl_link_i2name(link_cache, + msg->log_msg_indev, + buf, sizeof(buf))); + else + nl_dump(p, "IN=%d ", msg->log_msg_indev); + } + + if (msg->ce_mask & LOG_MSG_ATTR_PHYSINDEV) { + if (link_cache) + nl_dump(p, "PHYSIN=%s ", + rtnl_link_i2name(link_cache, + msg->log_msg_physindev, + buf, sizeof(buf))); + else + nl_dump(p, "IN=%d ", msg->log_msg_physindev); + } + + if (msg->ce_mask & LOG_MSG_ATTR_OUTDEV) { + if (link_cache) + nl_dump(p, "OUT=%s ", + rtnl_link_i2name(link_cache, + msg->log_msg_outdev, + buf, sizeof(buf))); + else + nl_dump(p, "OUT=%d ", msg->log_msg_outdev); + } + + if (msg->ce_mask & LOG_MSG_ATTR_PHYSOUTDEV) { + if (link_cache) + nl_dump(p, "PHYSOUT=%s ", + rtnl_link_i2name(link_cache, + msg->log_msg_physoutdev, + buf, sizeof(buf))); + else + nl_dump(p, "PHYSOUT=%d ", msg->log_msg_physoutdev); + } + + if (msg->ce_mask & LOG_MSG_ATTR_HWADDR) { + int i; + + nl_dump(p, "MAC"); + for (i = 0; i < msg->log_msg_hwaddr_len; i++) + nl_dump(p, "%c%02x", i?':':'=', msg->log_msg_hwaddr[i]); + nl_dump(p, " "); + } + + /* FIXME: parse the payload to get iptables LOG compatible format */ + + if (msg->ce_mask & LOG_MSG_ATTR_FAMILY) + nl_dump(p, "FAMILY=%s ", + nl_af2str(msg->log_msg_family, buf, sizeof(buf))); + + if (msg->ce_mask & LOG_MSG_ATTR_HWPROTO) + nl_dump(p, "HWPROTO=%s ", + nl_ether_proto2str(ntohs(msg->log_msg_hwproto), + buf, sizeof(buf))); + + if (msg->ce_mask & LOG_MSG_ATTR_HOOK) + nl_dump(p, "HOOK=%s ", + nfnl_inet_hook2str(msg->log_msg_hook, + buf, sizeof(buf))); + + if (msg->ce_mask & LOG_MSG_ATTR_MARK) + nl_dump(p, "MARK=%u ", msg->log_msg_mark); + + if (msg->ce_mask & LOG_MSG_ATTR_PAYLOAD) + nl_dump(p, "PAYLOADLEN=%d ", msg->log_msg_payload_len); + + if (msg->ce_mask & LOG_MSG_ATTR_UID) + nl_dump(p, "UID=%u ", msg->log_msg_uid); + + if (msg->ce_mask & LOG_MSG_ATTR_GID) + nl_dump(p, "GID=%u ", msg->log_msg_gid); + + if (msg->ce_mask & LOG_MSG_ATTR_SEQ) + nl_dump(p, "SEQ=%d ", msg->log_msg_seq); + + if (msg->ce_mask & LOG_MSG_ATTR_SEQ_GLOBAL) + nl_dump(p, "SEQGLOBAL=%d ", msg->log_msg_seq_global); + + nl_dump(p, "\n"); +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct nfnl_log_msg *nfnl_log_msg_alloc(void) +{ + return (struct nfnl_log_msg *) nl_object_alloc(&log_msg_obj_ops); +} + +void nfnl_log_msg_get(struct nfnl_log_msg *msg) +{ + nl_object_get((struct nl_object *) msg); +} + +void nfnl_log_msg_put(struct nfnl_log_msg *msg) +{ + nl_object_put((struct nl_object *) msg); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void nfnl_log_msg_set_family(struct nfnl_log_msg *msg, uint8_t family) +{ + msg->log_msg_family = family; + msg->ce_mask |= LOG_MSG_ATTR_FAMILY; +} + +uint8_t nfnl_log_msg_get_family(const struct nfnl_log_msg *msg) +{ + if (msg->ce_mask & LOG_MSG_ATTR_FAMILY) + return msg->log_msg_family; + else + return AF_UNSPEC; +} + +void nfnl_log_msg_set_hwproto(struct nfnl_log_msg *msg, uint16_t hwproto) +{ + msg->log_msg_hwproto = hwproto; + msg->ce_mask |= LOG_MSG_ATTR_HWPROTO; +} + +int nfnl_log_msg_test_hwproto(const struct nfnl_log_msg *msg) +{ + return !!(msg->ce_mask & LOG_MSG_ATTR_HWPROTO); +} + +uint16_t nfnl_log_msg_get_hwproto(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_hwproto; +} + +void nfnl_log_msg_set_hook(struct nfnl_log_msg *msg, uint8_t hook) +{ + msg->log_msg_hook = hook; + msg->ce_mask |= LOG_MSG_ATTR_HOOK; +} + +int nfnl_log_msg_test_hook(const struct nfnl_log_msg *msg) +{ + return !!(msg->ce_mask & LOG_MSG_ATTR_HOOK); +} + +uint8_t nfnl_log_msg_get_hook(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_hook; +} + +void nfnl_log_msg_set_mark(struct nfnl_log_msg *msg, uint32_t mark) +{ + msg->log_msg_mark = mark; + msg->ce_mask |= LOG_MSG_ATTR_MARK; +} + +int nfnl_log_msg_test_mark(const struct nfnl_log_msg *msg) +{ + return !!(msg->ce_mask & LOG_MSG_ATTR_MARK); +} + +uint32_t nfnl_log_msg_get_mark(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_mark; +} + +void nfnl_log_msg_set_timestamp(struct nfnl_log_msg *msg, struct timeval *tv) +{ + msg->log_msg_timestamp.tv_sec = tv->tv_sec; + msg->log_msg_timestamp.tv_usec = tv->tv_usec; + msg->ce_mask |= LOG_MSG_ATTR_TIMESTAMP; +} + +const struct timeval *nfnl_log_msg_get_timestamp(const struct nfnl_log_msg *msg) +{ + if (!(msg->ce_mask & LOG_MSG_ATTR_TIMESTAMP)) + return NULL; + return &msg->log_msg_timestamp; +} + +void nfnl_log_msg_set_indev(struct nfnl_log_msg *msg, uint32_t indev) +{ + msg->log_msg_indev = indev; + msg->ce_mask |= LOG_MSG_ATTR_INDEV; +} + +uint32_t nfnl_log_msg_get_indev(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_indev; +} + +void nfnl_log_msg_set_outdev(struct nfnl_log_msg *msg, uint32_t outdev) +{ + msg->log_msg_outdev = outdev; + msg->ce_mask |= LOG_MSG_ATTR_OUTDEV; +} + +uint32_t nfnl_log_msg_get_outdev(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_outdev; +} + +void nfnl_log_msg_set_physindev(struct nfnl_log_msg *msg, uint32_t physindev) +{ + msg->log_msg_physindev = physindev; + msg->ce_mask |= LOG_MSG_ATTR_PHYSINDEV; +} + +uint32_t nfnl_log_msg_get_physindev(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_physindev; +} + +void nfnl_log_msg_set_physoutdev(struct nfnl_log_msg *msg, uint32_t physoutdev) +{ + msg->log_msg_physoutdev = physoutdev; + msg->ce_mask |= LOG_MSG_ATTR_PHYSOUTDEV; +} + +uint32_t nfnl_log_msg_get_physoutdev(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_physoutdev; +} + +void nfnl_log_msg_set_hwaddr(struct nfnl_log_msg *msg, uint8_t *hwaddr, int len) +{ + if (len > sizeof(msg->log_msg_hwaddr)) + len = sizeof(msg->log_msg_hwaddr); + msg->log_msg_hwaddr_len = len; + memcpy(msg->log_msg_hwaddr, hwaddr, len); + msg->ce_mask |= LOG_MSG_ATTR_HWADDR; +} + +const uint8_t *nfnl_log_msg_get_hwaddr(const struct nfnl_log_msg *msg, int *len) +{ + if (!(msg->ce_mask & LOG_MSG_ATTR_HWADDR)) { + *len = 0; + return NULL; + } + + *len = msg->log_msg_hwaddr_len; + return msg->log_msg_hwaddr; +} + +int nfnl_log_msg_set_payload(struct nfnl_log_msg *msg, uint8_t *payload, int len) +{ + free(msg->log_msg_payload); + msg->log_msg_payload = malloc(len); + if (!msg->log_msg_payload) + return -NLE_NOMEM; + + memcpy(msg->log_msg_payload, payload, len); + msg->log_msg_payload_len = len; + msg->ce_mask |= LOG_MSG_ATTR_PAYLOAD; + return 0; +} + +const void *nfnl_log_msg_get_payload(const struct nfnl_log_msg *msg, int *len) +{ + if (!(msg->ce_mask & LOG_MSG_ATTR_PAYLOAD)) { + *len = 0; + return NULL; + } + + *len = msg->log_msg_payload_len; + return msg->log_msg_payload; +} + +int nfnl_log_msg_set_prefix(struct nfnl_log_msg *msg, void *prefix) +{ + free(msg->log_msg_prefix); + msg->log_msg_prefix = strdup(prefix); + if (!msg->log_msg_prefix) + return -NLE_NOMEM; + + msg->ce_mask |= LOG_MSG_ATTR_PREFIX; + return 0; +} + +const char *nfnl_log_msg_get_prefix(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_prefix; +} + +void nfnl_log_msg_set_uid(struct nfnl_log_msg *msg, uint32_t uid) +{ + msg->log_msg_uid = uid; + msg->ce_mask |= LOG_MSG_ATTR_UID; +} + +int nfnl_log_msg_test_uid(const struct nfnl_log_msg *msg) +{ + return !!(msg->ce_mask & LOG_MSG_ATTR_UID); +} + +uint32_t nfnl_log_msg_get_uid(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_uid; +} + +void nfnl_log_msg_set_gid(struct nfnl_log_msg *msg, uint32_t gid) +{ + msg->log_msg_gid = gid; + msg->ce_mask |= LOG_MSG_ATTR_GID; +} + +int nfnl_log_msg_test_gid(const struct nfnl_log_msg *msg) +{ + return !!(msg->ce_mask & LOG_MSG_ATTR_GID); +} + +uint32_t nfnl_log_msg_get_gid(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_gid; +} + + +void nfnl_log_msg_set_seq(struct nfnl_log_msg *msg, uint32_t seq) +{ + msg->log_msg_seq = seq; + msg->ce_mask |= LOG_MSG_ATTR_SEQ; +} + +int nfnl_log_msg_test_seq(const struct nfnl_log_msg *msg) +{ + return !!(msg->ce_mask & LOG_MSG_ATTR_SEQ); +} + +uint32_t nfnl_log_msg_get_seq(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_seq; +} + +void nfnl_log_msg_set_seq_global(struct nfnl_log_msg *msg, uint32_t seq_global) +{ + msg->log_msg_seq_global = seq_global; + msg->ce_mask |= LOG_MSG_ATTR_SEQ_GLOBAL; +} + +int nfnl_log_msg_test_seq_global(const struct nfnl_log_msg *msg) +{ + return !!(msg->ce_mask & LOG_MSG_ATTR_SEQ_GLOBAL); +} + +uint32_t nfnl_log_msg_get_seq_global(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_seq_global; +} + +/** @} */ + +struct nl_object_ops log_msg_obj_ops = { + .oo_name = "netfilter/log_msg", + .oo_size = sizeof(struct nfnl_log_msg), + .oo_free_data = log_msg_free_data, + .oo_clone = log_msg_clone, + .oo_dump = { + [NL_DUMP_LINE] = log_msg_dump, + [NL_DUMP_DETAILS] = log_msg_dump, + [NL_DUMP_STATS] = log_msg_dump, + }, +}; + +/** @} */ diff --git a/libnetwork/libnl3/lib/netfilter/log_obj.c b/libnetwork/libnl3/lib/netfilter/log_obj.c new file mode 100644 index 0000000..43c4a06 --- /dev/null +++ b/libnetwork/libnl3/lib/netfilter/log_obj.c @@ -0,0 +1,287 @@ +/* + * lib/netfilter/log_obj.c Netfilter Log Object + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + * Copyright (c) 2007 Philip Craig + * Copyright (c) 2007 Secure Computing Corporation + * Copyright (c) 2008 Patrick McHardy + */ + +#include +#include +#include + +/** @cond SKIP */ +#define LOG_ATTR_GROUP (1UL << 0) +#define LOG_ATTR_COPY_MODE (1UL << 1) +#define LOG_ATTR_COPY_RANGE (1UL << 3) +#define LOG_ATTR_FLUSH_TIMEOUT (1UL << 4) +#define LOG_ATTR_ALLOC_SIZE (1UL << 5) +#define LOG_ATTR_QUEUE_THRESHOLD (1UL << 6) + +/** @endcond */ + +static void nfnl_log_dump(struct nl_object *a, struct nl_dump_params *p) +{ + struct nfnl_log *log = (struct nfnl_log *) a; + char buf[64]; + + nl_new_line(p); + + if (log->ce_mask & LOG_ATTR_GROUP) + nl_dump(p, "group=%u ", log->log_group); + + if (log->ce_mask & LOG_ATTR_COPY_MODE) + nl_dump(p, "copy_mode=%s ", + nfnl_log_copy_mode2str(log->log_copy_mode, + buf, sizeof(buf))); + + if (log->ce_mask & LOG_ATTR_COPY_RANGE) + nl_dump(p, "copy_range=%u ", log->log_copy_range); + + if (log->ce_mask & LOG_ATTR_FLUSH_TIMEOUT) + nl_dump(p, "flush_timeout=%u ", log->log_flush_timeout); + + if (log->ce_mask & LOG_ATTR_ALLOC_SIZE) + nl_dump(p, "alloc_size=%u ", log->log_alloc_size); + + if (log->ce_mask & LOG_ATTR_QUEUE_THRESHOLD) + nl_dump(p, "queue_threshold=%u ", log->log_queue_threshold); + + nl_dump(p, "\n"); +} + +static const struct trans_tbl copy_modes[] = { + __ADD(NFNL_LOG_COPY_NONE, none) + __ADD(NFNL_LOG_COPY_META, meta) + __ADD(NFNL_LOG_COPY_PACKET, packet) +}; + +char *nfnl_log_copy_mode2str(enum nfnl_log_copy_mode copy_mode, char *buf, + size_t len) +{ + return __type2str(copy_mode, buf, len, copy_modes, + ARRAY_SIZE(copy_modes)); +} + +enum nfnl_log_copy_mode nfnl_log_str2copy_mode(const char *name) +{ + return __str2type(name, copy_modes, ARRAY_SIZE(copy_modes)); +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct nfnl_log *nfnl_log_alloc(void) +{ + return (struct nfnl_log *) nl_object_alloc(&log_obj_ops); +} + +void nfnl_log_get(struct nfnl_log *log) +{ + nl_object_get((struct nl_object *) log); +} + +void nfnl_log_put(struct nfnl_log *log) +{ + nl_object_put((struct nl_object *) log); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void nfnl_log_set_group(struct nfnl_log *log, uint16_t group) +{ + log->log_group = group; + log->ce_mask |= LOG_ATTR_GROUP; +} + +int nfnl_log_test_group(const struct nfnl_log *log) +{ + return !!(log->ce_mask & LOG_ATTR_GROUP); +} + +uint16_t nfnl_log_get_group(const struct nfnl_log *log) +{ + return log->log_group; +} + +void nfnl_log_set_copy_mode(struct nfnl_log *log, enum nfnl_log_copy_mode mode) +{ + log->log_copy_mode = mode; + log->ce_mask |= LOG_ATTR_COPY_MODE; +} + +int nfnl_log_test_copy_mode(const struct nfnl_log *log) +{ + return !!(log->ce_mask & LOG_ATTR_COPY_MODE); +} + +enum nfnl_log_copy_mode nfnl_log_get_copy_mode(const struct nfnl_log *log) +{ + return log->log_copy_mode; +} + +void nfnl_log_set_copy_range(struct nfnl_log *log, uint32_t copy_range) +{ + log->log_copy_range = copy_range; + log->ce_mask |= LOG_ATTR_COPY_RANGE; +} + +int nfnl_log_test_copy_range(const struct nfnl_log *log) +{ + return !!(log->ce_mask & LOG_ATTR_COPY_RANGE); +} + +uint32_t nfnl_log_get_copy_range(const struct nfnl_log *log) +{ + return log->log_copy_range; +} + +void nfnl_log_set_flush_timeout(struct nfnl_log *log, uint32_t timeout) +{ + log->log_flush_timeout = timeout; + log->ce_mask |= LOG_ATTR_FLUSH_TIMEOUT; +} + +int nfnl_log_test_flush_timeout(const struct nfnl_log *log) +{ + return !!(log->ce_mask & LOG_ATTR_FLUSH_TIMEOUT); +} + +uint32_t nfnl_log_get_flush_timeout(const struct nfnl_log *log) +{ + return log->log_flush_timeout; +} + +void nfnl_log_set_alloc_size(struct nfnl_log *log, uint32_t alloc_size) +{ + log->log_alloc_size = alloc_size; + log->ce_mask |= LOG_ATTR_ALLOC_SIZE; +} + +int nfnl_log_test_alloc_size(const struct nfnl_log *log) +{ + return !!(log->ce_mask & LOG_ATTR_ALLOC_SIZE); +} + +uint32_t nfnl_log_get_alloc_size(const struct nfnl_log *log) +{ + return log->log_alloc_size; +} + +void nfnl_log_set_queue_threshold(struct nfnl_log *log, uint32_t threshold) +{ + log->log_queue_threshold = threshold; + log->ce_mask |= LOG_ATTR_QUEUE_THRESHOLD; +} + +int nfnl_log_test_queue_threshold(const struct nfnl_log *log) +{ + return !!(log->ce_mask & LOG_ATTR_QUEUE_THRESHOLD); +} + +uint32_t nfnl_log_get_queue_threshold(const struct nfnl_log *log) +{ + return log->log_queue_threshold; +} + +/* We don't actually use the flags for anything yet since the + * nfnetlog_log interface truly sucks - it only contains the + * flag value, but not mask, so we would have to make assumptions + * about the supported flags. + */ +void nfnl_log_set_flags(struct nfnl_log *log, unsigned int flags) +{ + log->log_flags |= flags; + log->log_flag_mask |= flags; +} + +void nfnl_log_unset_flags(struct nfnl_log *log, unsigned int flags) +{ + log->log_flags &= ~flags; + log->log_flag_mask |= flags; +} + +static const struct trans_tbl log_flags[] = { + __ADD(NFNL_LOG_FLAG_SEQ, seq) + __ADD(NFNL_LOG_FLAG_SEQ_GLOBAL, seq_global) +}; + +char *nfnl_log_flags2str(unsigned int flags, char *buf, size_t len) +{ + return __flags2str(flags, buf, len, log_flags, ARRAY_SIZE(log_flags)); +} + +unsigned int nfnl_log_str2flags(const char *name) +{ + return __str2flags(name, log_flags, ARRAY_SIZE(log_flags)); +} + +static int nfnl_log_compare(struct nl_object *_a, struct nl_object *_b, + uint32_t attrs, int flags) +{ + struct nfnl_log *a = (struct nfnl_log *) _a; + struct nfnl_log *b = (struct nfnl_log *) _b; + int diff = 0; + +#define NFNL_LOG_DIFF(ATTR, EXPR) \ + ATTR_DIFF(attrs, LOG_ATTR_##ATTR, a, b, EXPR) +#define NFNL_LOG_DIFF_VAL(ATTR, FIELD) \ + NFNL_LOG_DIFF(ATTR, a->FIELD != b->FIELD) + + diff |= NFNL_LOG_DIFF_VAL(GROUP, log_group); + diff |= NFNL_LOG_DIFF_VAL(COPY_MODE, log_copy_mode); + diff |= NFNL_LOG_DIFF_VAL(COPY_RANGE, log_copy_range); + diff |= NFNL_LOG_DIFF_VAL(FLUSH_TIMEOUT, log_flush_timeout); + diff |= NFNL_LOG_DIFF_VAL(ALLOC_SIZE, log_alloc_size); + diff |= NFNL_LOG_DIFF_VAL(QUEUE_THRESHOLD, log_queue_threshold); + +#undef NFNL_LOG_DIFF +#undef NFNL_LOG_DIFF_VAL + + return diff; +} + +static const struct trans_tbl nfnl_log_attrs[] = { + __ADD(LOG_ATTR_GROUP, group) + __ADD(LOG_ATTR_COPY_MODE, copy_mode) + __ADD(LOG_ATTR_COPY_RANGE, copy_range) + __ADD(LOG_ATTR_FLUSH_TIMEOUT, flush_timeout) + __ADD(LOG_ATTR_ALLOC_SIZE, alloc_size) + __ADD(LOG_ATTR_QUEUE_THRESHOLD, queue_threshold) +}; + +static char *nfnl_log_attrs2str(int attrs, char *buf, size_t len) +{ + return __flags2str(attrs, buf, len, nfnl_log_attrs, + ARRAY_SIZE(nfnl_log_attrs)); +} + +/** @} */ + +struct nl_object_ops log_obj_ops = { + .oo_name = "netfilter/log", + .oo_size = sizeof(struct nfnl_log), + .oo_dump = { + [NL_DUMP_LINE] = nfnl_log_dump, + [NL_DUMP_DETAILS] = nfnl_log_dump, + [NL_DUMP_STATS] = nfnl_log_dump, + }, + .oo_compare = nfnl_log_compare, + .oo_attrs2str = nfnl_log_attrs2str, + .oo_id_attrs = LOG_ATTR_GROUP, +}; + +/** @} */ diff --git a/libnetwork/libnl3/lib/netfilter/netfilter.c b/libnetwork/libnl3/lib/netfilter/netfilter.c new file mode 100644 index 0000000..addecd7 --- /dev/null +++ b/libnetwork/libnl3/lib/netfilter/netfilter.c @@ -0,0 +1,53 @@ +/* + * lib/netfilter/netfilter.c Netfilter Generic Functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Patrick McHardy + */ + +#include +#include +#include + +static const struct trans_tbl nfnl_verdicts[] = { + __ADD(NF_DROP, NF_DROP) + __ADD(NF_ACCEPT, NF_ACCEPT) + __ADD(NF_STOLEN, NF_STOLEN) + __ADD(NF_QUEUE, NF_QUEUE) + __ADD(NF_REPEAT, NF_REPEAT) + __ADD(NF_STOP, NF_STOP) +}; + +char *nfnl_verdict2str(unsigned int verdict, char *buf, size_t len) +{ + return __type2str(verdict, buf, len, nfnl_verdicts, + ARRAY_SIZE(nfnl_verdicts)); +} + +unsigned int nfnl_str2verdict(const char *name) +{ + return __str2type(name, nfnl_verdicts, ARRAY_SIZE(nfnl_verdicts)); +} + +static const struct trans_tbl nfnl_inet_hooks[] = { + __ADD(NF_INET_PRE_ROUTING, NF_INET_PREROUTING) + __ADD(NF_INET_LOCAL_IN, NF_INET_LOCAL_IN) + __ADD(NF_INET_FORWARD, NF_INET_FORWARD) + __ADD(NF_INET_LOCAL_OUT, NF_INET_LOCAL_OUT) + __ADD(NF_INET_POST_ROUTING, NF_INET_POST_ROUTING) +}; + +char *nfnl_inet_hook2str(unsigned int hook, char *buf, size_t len) +{ + return __type2str(hook, buf, len, nfnl_inet_hooks, + ARRAY_SIZE(nfnl_inet_hooks)); +} + +unsigned int nfnl_str2inet_hook(const char *name) +{ + return __str2type(name, nfnl_inet_hooks, ARRAY_SIZE(nfnl_inet_hooks)); +} diff --git a/libnetwork/libnl3/lib/netfilter/nfnl.c b/libnetwork/libnl3/lib/netfilter/nfnl.c new file mode 100644 index 0000000..ddce4b9 --- /dev/null +++ b/libnetwork/libnl3/lib/netfilter/nfnl.c @@ -0,0 +1,245 @@ +/* + * lib/netfilter/nfnl.c Netfilter Netlink + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + * Copyright (c) 2007 Philip Craig + * Copyright (c) 2007 Secure Computing Corporation + */ + +/** + * @defgroup nfnl Netfilter Netlink + * + * @par Message Format + * @code + * <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) ---> + * +----------------------------+- - -+- - - - - - - - - - -+- - -+ + * | Header | Pad | Payload | Pad | + * | struct nlmsghdr | | | | + * +----------------------------+- - -+- - - - - - - - - - -+- - -+ + * @endcode + * @code + * <-------- NFNL_HDRLEN ---------> + * +--------------------------+- - -+------------+ + * | Netfilter Netlink Header | Pad | Attributes | + * | struct nfgenmsg | | | + * +--------------------------+- - -+------------+ + * nfnlmsg_attrdata(nfg, hdrlen)-----^ + * @endcode + * + * @par 1) Creating a new netfilter netlink message + * @code + * struct nl_msg *msg; + * + * // Create a new empty netlink message + * msg = nlmsg_alloc(); + * + * // Append the netlink and netfilter netlink message header + * hdr = nfnlmsg_put(msg, PID, SEQ, SUBSYS, TYPE, NLM_F_ECHO, + * FAMILY, RES_ID); + * + * // Append the attributes. + * nla_put_u32(msg, 1, 0x10); + * + * // Message is ready to be sent. + * nl_send_auto_complete(sk, msg); + * + * // All done? Free the message. + * nlmsg_free(msg); + * @endcode + * + * @par 2) Sending of trivial messages + * @code + * // For trivial messages not requiring any subsys specific header or + * // attributes, nfnl_send_simple() may be used to send messages directly. + * nfnl_send_simple(sk, SUBSYS, TYPE, 0, FAMILY, RES_ID); + * @endcode + * @{ + */ + +#include +#include +#include + +/** + * @name Socket Creating + * @{ + */ + +/** + * Create and connect netfilter netlink socket. + * @arg sk Netlink socket. + * + * Creates a NETLINK_NETFILTER netlink socket, binds the socket and + * issues a connection attempt. + * + * @see nl_connect() + * + * @return 0 on success or a negative error code. + */ +int nfnl_connect(struct nl_sock *sk) +{ + return nl_connect(sk, NETLINK_NETFILTER); +} + +/** @} */ + +/** + * @name Sending + * @{ + */ + +/** + * Send trivial netfilter netlink message + * @arg sk Netlink socket. + * @arg subsys_id nfnetlink subsystem + * @arg type nfnetlink message type + * @arg flags message flags + * @arg family nfnetlink address family + * @arg res_id nfnetlink resource id + * + * @return Newly allocated netlink message or NULL. + */ +int nfnl_send_simple(struct nl_sock *sk, uint8_t subsys_id, uint8_t type, + int flags, uint8_t family, uint16_t res_id) +{ + struct nfgenmsg hdr = { + .nfgen_family = family, + .version = NFNETLINK_V0, + .res_id = htons(res_id), + }; + + return nl_send_simple(sk, NFNLMSG_TYPE(subsys_id, type), flags, + &hdr, sizeof(hdr)); +} + +/** @} */ + +/** + * @name Message Parsing + * @{ + */ + +/** + * Get netfilter subsystem id from message + * @arg nlh netlink messsage header + */ +uint8_t nfnlmsg_subsys(struct nlmsghdr *nlh) +{ + return NFNL_SUBSYS_ID(nlh->nlmsg_type); +} + +/** + * Get netfilter message type from message + * @arg nlh netlink messsage header + */ +uint8_t nfnlmsg_subtype(struct nlmsghdr *nlh) +{ + return NFNL_MSG_TYPE(nlh->nlmsg_type); +} + +/** + * Get netfilter family from message + * @arg nlh netlink messsage header + */ +uint8_t nfnlmsg_family(struct nlmsghdr *nlh) +{ + struct nfgenmsg *nfg = nlmsg_data(nlh); + + return nfg->nfgen_family; +} + +/** + * Get netfilter resource id from message + * @arg nlh netlink messsage header + */ +uint16_t nfnlmsg_res_id(struct nlmsghdr *nlh) +{ + struct nfgenmsg *nfg = nlmsg_data(nlh); + + return ntohs(nfg->res_id); +} + +/** @} */ + +/** + * @name Message Building + * @{ + */ + +static int nfnlmsg_append(struct nl_msg *msg, uint8_t family, uint16_t res_id) +{ + struct nfgenmsg *nfg; + + nfg = nlmsg_reserve(msg, sizeof(*nfg), NLMSG_ALIGNTO); + if (nfg == NULL) + return -NLE_NOMEM; + + nfg->nfgen_family = family; + nfg->version = NFNETLINK_V0; + nfg->res_id = htons(res_id); + NL_DBG(2, "msg %p: Added nfnetlink header family=%d res_id=%d\n", + msg, family, res_id); + return 0; +} + +/** + * Allocate a new netfilter netlink message + * @arg subsys_id nfnetlink subsystem + * @arg type nfnetlink message type + * @arg flags message flags + * @arg family nfnetlink address family + * @arg res_id nfnetlink resource id + * + * @return Newly allocated netlink message or NULL. + */ +struct nl_msg *nfnlmsg_alloc_simple(uint8_t subsys_id, uint8_t type, int flags, + uint8_t family, uint16_t res_id) +{ + struct nl_msg *msg; + + msg = nlmsg_alloc_simple(NFNLMSG_TYPE(subsys_id, type), flags); + if (msg == NULL) + return NULL; + + if (nfnlmsg_append(msg, family, res_id) < 0) + goto nla_put_failure; + + return msg; + +nla_put_failure: + nlmsg_free(msg); + return NULL; +} + +/** + * Add netlink and netfilter netlink headers to netlink message + * @arg msg netlink message + * @arg pid netlink process id + * @arg seq sequence number of message + * @arg subsys_id nfnetlink subsystem + * @arg type nfnetlink message type + * @arg flags message flags + * @arg family nfnetlink address family + * @arg res_id nfnetlink resource id + */ +int nfnlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, + uint8_t subsys_id, uint8_t type, int flags, uint8_t family, + uint16_t res_id) +{ + struct nlmsghdr *nlh; + + nlh = nlmsg_put(msg, pid, seq, NFNLMSG_TYPE(subsys_id, type), 0, flags); + if (nlh == NULL) + return -NLE_MSGSIZE; + + return nfnlmsg_append(msg, family, res_id); +} + +/** @} */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/netfilter/queue.c b/libnetwork/libnl3/lib/netfilter/queue.c new file mode 100644 index 0000000..ff1de0e --- /dev/null +++ b/libnetwork/libnl3/lib/netfilter/queue.c @@ -0,0 +1,251 @@ +/* + * lib/netfilter/queue.c Netfilter Queue + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2007, 2008 Patrick McHardy + */ + +/** + * @ingroup nfnl + * @defgroup queue Queue + * @brief + * @{ + */ + +#include +#include + +#include +#include +#include +#include + +struct nl_sock *nfnl_queue_socket_alloc(void) +{ + struct nl_sock *nlsk; + + nlsk = nl_socket_alloc(); + if (nlsk) + nl_socket_disable_auto_ack(nlsk); + return nlsk; +} + +static int send_queue_request(struct nl_sock *sk, struct nl_msg *msg) +{ + int err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +/** + * @name Queue Commands + * @{ + */ + +static int build_queue_cmd_request(uint8_t family, uint16_t queuenum, + uint8_t command, struct nl_msg **result) +{ + struct nl_msg *msg; + struct nfqnl_msg_config_cmd cmd; + + msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0, + family, queuenum); + if (msg == NULL) + return -NLE_NOMEM; + + cmd.pf = htons(family); + cmd._pad = 0; + cmd.command = command; + if (nla_put(msg, NFQA_CFG_CMD, sizeof(cmd), &cmd) < 0) + goto nla_put_failure; + + *result = msg; + return 0; + +nla_put_failure: + nlmsg_free(msg); + return -NLE_MSGSIZE; +} + +int nfnl_queue_build_pf_bind(uint8_t pf, struct nl_msg **result) +{ + return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_BIND, result); +} + +int nfnl_queue_pf_bind(struct nl_sock *nlh, uint8_t pf) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_queue_build_pf_bind(pf, &msg)) < 0) + return err; + + return send_queue_request(nlh, msg); +} + +int nfnl_queue_build_pf_unbind(uint8_t pf, struct nl_msg **result) +{ + return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_UNBIND, result); +} + +int nfnl_queue_pf_unbind(struct nl_sock *nlh, uint8_t pf) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_queue_build_pf_unbind(pf, &msg)) < 0) + return err; + + return send_queue_request(nlh, msg); +} + +static int nfnl_queue_build_request(const struct nfnl_queue *queue, + struct nl_msg **result) +{ + struct nl_msg *msg; + + if (!nfnl_queue_test_group(queue)) + return -NLE_MISSING_ATTR; + + msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0, + 0, nfnl_queue_get_group(queue)); + if (msg == NULL) + return -NLE_NOMEM; + + if (nfnl_queue_test_maxlen(queue) && + nla_put_u32(msg, NFQA_CFG_QUEUE_MAXLEN, + htonl(nfnl_queue_get_maxlen(queue))) < 0) + goto nla_put_failure; + + /* This sucks, the nfnetlink_queue interface always expects both + * parameters to be present. Needs to be done properly. + */ + if (nfnl_queue_test_copy_mode(queue)) { + struct nfqnl_msg_config_params params; + + switch (nfnl_queue_get_copy_mode(queue)) { + case NFNL_QUEUE_COPY_NONE: + params.copy_mode = NFQNL_COPY_NONE; + break; + case NFNL_QUEUE_COPY_META: + params.copy_mode = NFQNL_COPY_META; + break; + case NFNL_QUEUE_COPY_PACKET: + params.copy_mode = NFQNL_COPY_PACKET; + break; + } + params.copy_range = htonl(nfnl_queue_get_copy_range(queue)); + + if (nla_put(msg, NFQA_CFG_PARAMS, sizeof(params), ¶ms) < 0) + goto nla_put_failure; + } + + *result = msg; + return 0; + +nla_put_failure: + nlmsg_free(msg); + return -NLE_MSGSIZE; +} + +int nfnl_queue_build_create_request(const struct nfnl_queue *queue, + struct nl_msg **result) +{ + struct nfqnl_msg_config_cmd cmd; + int err; + + if ((err = nfnl_queue_build_request(queue, result)) < 0) + return err; + + cmd.pf = 0; + cmd._pad = 0; + cmd.command = NFQNL_CFG_CMD_BIND; + + NLA_PUT(*result, NFQA_CFG_CMD, sizeof(cmd), &cmd); + + return 0; + +nla_put_failure: + nlmsg_free(*result); + return -NLE_MSGSIZE; +} + +int nfnl_queue_create(struct nl_sock *nlh, const struct nfnl_queue *queue) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_queue_build_create_request(queue, &msg)) < 0) + return err; + + return send_queue_request(nlh, msg); +} + +int nfnl_queue_build_change_request(const struct nfnl_queue *queue, + struct nl_msg **result) +{ + return nfnl_queue_build_request(queue, result); +} + +int nfnl_queue_change(struct nl_sock *nlh, const struct nfnl_queue *queue) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_queue_build_change_request(queue, &msg)) < 0) + return err; + + return send_queue_request(nlh, msg); +} + +int nfnl_queue_build_delete_request(const struct nfnl_queue *queue, + struct nl_msg **result) +{ + if (!nfnl_queue_test_group(queue)) + return -NLE_MISSING_ATTR; + + return build_queue_cmd_request(0, nfnl_queue_get_group(queue), + NFQNL_CFG_CMD_UNBIND, result); +} + +int nfnl_queue_delete(struct nl_sock *nlh, const struct nfnl_queue *queue) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_queue_build_delete_request(queue, &msg)) < 0) + return err; + + return send_queue_request(nlh, msg); +} + +/** @} */ + +static struct nl_cache_ops nfnl_queue_ops = { + .co_name = "netfilter/queue", + .co_obj_ops = &queue_obj_ops, + .co_msgtypes = { + END_OF_MSGTYPES_LIST, + }, +}; + +static void __init nfnl_queue_init(void) +{ + nl_cache_mngt_register(&nfnl_queue_ops); +} + +static void __exit nfnl_queue_exit(void) +{ + nl_cache_mngt_unregister(&nfnl_queue_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/netfilter/queue_msg.c b/libnetwork/libnl3/lib/netfilter/queue_msg.c new file mode 100644 index 0000000..c40f8c2 --- /dev/null +++ b/libnetwork/libnl3/lib/netfilter/queue_msg.c @@ -0,0 +1,284 @@ +/* + * lib/netfilter/queue_msg.c Netfilter Queue Messages + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2007, 2008 Patrick McHardy + * Copyright (c) 2010 Karl Hiramoto + */ + +/** + * @ingroup nfnl + * @defgroup queue Queue + * @brief + * @{ + */ + +#include +#include + +#include +#include +#include +#include + +static struct nl_cache_ops nfnl_queue_msg_ops; + +#if __BYTE_ORDER == __BIG_ENDIAN +static uint64_t ntohll(uint64_t x) +{ + return x; +} +#elif __BYTE_ORDER == __LITTLE_ENDIAN +static uint64_t ntohll(uint64_t x) +{ + return __bswap_64(x); +} +#endif + +static struct nla_policy queue_policy[NFQA_MAX+1] = { + [NFQA_PACKET_HDR] = { + .minlen = sizeof(struct nfqnl_msg_packet_hdr), + }, + [NFQA_VERDICT_HDR] = { + .minlen = sizeof(struct nfqnl_msg_verdict_hdr), + }, + [NFQA_MARK] = { .type = NLA_U32 }, + [NFQA_TIMESTAMP] = { + .minlen = sizeof(struct nfqnl_msg_packet_timestamp), + }, + [NFQA_IFINDEX_INDEV] = { .type = NLA_U32 }, + [NFQA_IFINDEX_OUTDEV] = { .type = NLA_U32 }, + [NFQA_IFINDEX_PHYSINDEV] = { .type = NLA_U32 }, + [NFQA_IFINDEX_PHYSOUTDEV] = { .type = NLA_U32 }, + [NFQA_HWADDR] = { + .minlen = sizeof(struct nfqnl_msg_packet_hw), + }, +}; + +int nfnlmsg_queue_msg_parse(struct nlmsghdr *nlh, + struct nfnl_queue_msg **result) +{ + struct nfnl_queue_msg *msg; + struct nlattr *tb[NFQA_MAX+1]; + struct nlattr *attr; + int err; + + msg = nfnl_queue_msg_alloc(); + if (!msg) + return -NLE_NOMEM; + + msg->ce_msgtype = nlh->nlmsg_type; + + err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, NFQA_MAX, + queue_policy); + if (err < 0) + goto errout; + + nfnl_queue_msg_set_group(msg, nfnlmsg_res_id(nlh)); + nfnl_queue_msg_set_family(msg, nfnlmsg_family(nlh)); + + attr = tb[NFQA_PACKET_HDR]; + if (attr) { + struct nfqnl_msg_packet_hdr *hdr = nla_data(attr); + + nfnl_queue_msg_set_packetid(msg, ntohl(hdr->packet_id)); + if (hdr->hw_protocol) + nfnl_queue_msg_set_hwproto(msg, hdr->hw_protocol); + nfnl_queue_msg_set_hook(msg, hdr->hook); + } + + attr = tb[NFQA_MARK]; + if (attr) + nfnl_queue_msg_set_mark(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFQA_TIMESTAMP]; + if (attr) { + struct nfqnl_msg_packet_timestamp *timestamp = nla_data(attr); + struct timeval tv; + + tv.tv_sec = ntohll(timestamp->sec); + tv.tv_usec = ntohll(timestamp->usec); + nfnl_queue_msg_set_timestamp(msg, &tv); + } + + attr = tb[NFQA_IFINDEX_INDEV]; + if (attr) + nfnl_queue_msg_set_indev(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFQA_IFINDEX_OUTDEV]; + if (attr) + nfnl_queue_msg_set_outdev(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFQA_IFINDEX_PHYSINDEV]; + if (attr) + nfnl_queue_msg_set_physindev(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFQA_IFINDEX_PHYSOUTDEV]; + if (attr) + nfnl_queue_msg_set_physoutdev(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFQA_HWADDR]; + if (attr) { + struct nfqnl_msg_packet_hw *hw = nla_data(attr); + + nfnl_queue_msg_set_hwaddr(msg, hw->hw_addr, + ntohs(hw->hw_addrlen)); + } + + attr = tb[NFQA_PAYLOAD]; + if (attr) { + err = nfnl_queue_msg_set_payload(msg, nla_data(attr), + nla_len(attr)); + if (err < 0) + goto errout; + } + + *result = msg; + return 0; + +errout: + nfnl_queue_msg_put(msg); + return err; +} + +static int queue_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *nlh, struct nl_parser_param *pp) +{ + struct nfnl_queue_msg *msg; + int err; + + if ((err = nfnlmsg_queue_msg_parse(nlh, &msg)) < 0) + goto errout; + + err = pp->pp_cb((struct nl_object *) msg, pp); +errout: + nfnl_queue_msg_put(msg); + return err; +} + +/** @} */ + +struct nl_msg *nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *msg) +{ + struct nl_msg *nlmsg; + struct nfqnl_msg_verdict_hdr verdict; + + nlmsg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_VERDICT, 0, + nfnl_queue_msg_get_family(msg), + nfnl_queue_msg_get_group(msg)); + if (nlmsg == NULL) + return NULL; + + verdict.id = htonl(nfnl_queue_msg_get_packetid(msg)); + verdict.verdict = htonl(nfnl_queue_msg_get_verdict(msg)); + if (nla_put(nlmsg, NFQA_VERDICT_HDR, sizeof(verdict), &verdict) < 0) + goto nla_put_failure; + + if (nfnl_queue_msg_test_mark(msg) && + nla_put_u32(nlmsg, NFQA_MARK, + ntohl(nfnl_queue_msg_get_mark(msg))) < 0) + goto nla_put_failure; + + return nlmsg; + +nla_put_failure: + nlmsg_free(nlmsg); + return NULL; +} + +/** +* Send a message verdict/mark +* @arg nlh netlink messsage header +* @arg msg queue msg +* @return 0 on OK or error code +*/ +int nfnl_queue_msg_send_verdict(struct nl_sock *nlh, + const struct nfnl_queue_msg *msg) +{ + struct nl_msg *nlmsg; + int err; + + nlmsg = nfnl_queue_msg_build_verdict(msg); + if (nlmsg == NULL) + return -NLE_NOMEM; + + err = nl_send_auto_complete(nlh, nlmsg); + nlmsg_free(nlmsg); + if (err < 0) + return err; + return wait_for_ack(nlh); +} + +/** +* Send a message verdict including the payload +* @arg nlh netlink messsage header +* @arg msg queue msg +* @arg payload_data packet payload data +* @arg payload_len payload length +* @return 0 on OK or error code +*/ +int nfnl_queue_msg_send_verdict_payload(struct nl_sock *nlh, + const struct nfnl_queue_msg *msg, + const void *payload_data, unsigned payload_len) +{ + struct nl_msg *nlmsg; + int err; + struct iovec iov[3]; + struct nlattr nla; + + nlmsg = nfnl_queue_msg_build_verdict(msg); + if (nlmsg == NULL) + return -NLE_NOMEM; + + memset(iov, 0, sizeof(iov)); + + iov[0].iov_base = (void *) nlmsg_hdr(nlmsg); + iov[0].iov_len = nlmsg_hdr(nlmsg)->nlmsg_len; + + nla.nla_type = NFQA_PAYLOAD; + nla.nla_len = payload_len + sizeof(nla); + nlmsg_hdr(nlmsg)->nlmsg_len += nla.nla_len; + + iov[1].iov_base = (void *) &nla; + iov[1].iov_len = sizeof(nla); + + iov[2].iov_base = (void *) payload_data; + iov[2].iov_len = NLA_ALIGN(payload_len); + + nl_complete_msg(nlh, nlmsg); + err = nl_send_iovec(nlh, nlmsg, iov, 3); + + nlmsg_free(nlmsg); + if (err < 0) + return err; + return wait_for_ack(nlh); +} + +#define NFNLMSG_QUEUE_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_QUEUE, (type)) +static struct nl_cache_ops nfnl_queue_msg_ops = { + .co_name = "netfilter/queue_msg", + .co_hdrsize = NFNL_HDRLEN, + .co_msgtypes = { + { NFNLMSG_QUEUE_TYPE(NFQNL_MSG_PACKET), NL_ACT_NEW, "new" }, + END_OF_MSGTYPES_LIST, + }, + .co_protocol = NETLINK_NETFILTER, + .co_msg_parser = queue_msg_parser, + .co_obj_ops = &queue_msg_obj_ops, +}; + +static void __init nfnl_msg_queue_init(void) +{ + nl_cache_mngt_register(&nfnl_queue_msg_ops); +} + +static void __exit nfnl_queue_msg_exit(void) +{ + nl_cache_mngt_unregister(&nfnl_queue_msg_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/netfilter/queue_msg_obj.c b/libnetwork/libnl3/lib/netfilter/queue_msg_obj.c new file mode 100644 index 0000000..33305ed --- /dev/null +++ b/libnetwork/libnl3/lib/netfilter/queue_msg_obj.c @@ -0,0 +1,492 @@ +/* + * lib/netfilter/queue_msg_obj.c Netfilter Queue Message Object + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2007, 2008 Patrick McHardy + */ + +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define QUEUE_MSG_ATTR_GROUP (1UL << 0) +#define QUEUE_MSG_ATTR_FAMILY (1UL << 1) +#define QUEUE_MSG_ATTR_PACKETID (1UL << 2) +#define QUEUE_MSG_ATTR_HWPROTO (1UL << 3) +#define QUEUE_MSG_ATTR_HOOK (1UL << 4) +#define QUEUE_MSG_ATTR_MARK (1UL << 5) +#define QUEUE_MSG_ATTR_TIMESTAMP (1UL << 6) +#define QUEUE_MSG_ATTR_INDEV (1UL << 7) +#define QUEUE_MSG_ATTR_OUTDEV (1UL << 8) +#define QUEUE_MSG_ATTR_PHYSINDEV (1UL << 9) +#define QUEUE_MSG_ATTR_PHYSOUTDEV (1UL << 10) +#define QUEUE_MSG_ATTR_HWADDR (1UL << 11) +#define QUEUE_MSG_ATTR_PAYLOAD (1UL << 12) +#define QUEUE_MSG_ATTR_VERDICT (1UL << 13) +/** @endcond */ + +static void nfnl_queue_msg_free_data(struct nl_object *c) +{ + struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) c; + + if (msg == NULL) + return; + + free(msg->queue_msg_payload); +} + +static int nfnl_queue_msg_clone(struct nl_object *_dst, struct nl_object *_src) +{ + struct nfnl_queue_msg *dst = (struct nfnl_queue_msg *) _dst; + struct nfnl_queue_msg *src = (struct nfnl_queue_msg *) _src; + int err; + + if (src->queue_msg_payload) { + err = nfnl_queue_msg_set_payload(dst, src->queue_msg_payload, + src->queue_msg_payload_len); + if (err < 0) + goto errout; + } + + return 0; +errout: + return err; +} + +static void nfnl_queue_msg_dump(struct nl_object *a, struct nl_dump_params *p) +{ + struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) a; + struct nl_cache *link_cache; + char buf[64]; + + link_cache = nl_cache_mngt_require("route/link"); + + nl_new_line(p); + + if (msg->ce_mask & QUEUE_MSG_ATTR_GROUP) + nl_dump(p, "GROUP=%u ", msg->queue_msg_group); + + if (msg->ce_mask & QUEUE_MSG_ATTR_INDEV) { + if (link_cache) + nl_dump(p, "IN=%s ", + rtnl_link_i2name(link_cache, + msg->queue_msg_indev, + buf, sizeof(buf))); + else + nl_dump(p, "IN=%d ", msg->queue_msg_indev); + } + + if (msg->ce_mask & QUEUE_MSG_ATTR_PHYSINDEV) { + if (link_cache) + nl_dump(p, "PHYSIN=%s ", + rtnl_link_i2name(link_cache, + msg->queue_msg_physindev, + buf, sizeof(buf))); + else + nl_dump(p, "IN=%d ", msg->queue_msg_physindev); + } + + if (msg->ce_mask & QUEUE_MSG_ATTR_OUTDEV) { + if (link_cache) + nl_dump(p, "OUT=%s ", + rtnl_link_i2name(link_cache, + msg->queue_msg_outdev, + buf, sizeof(buf))); + else + nl_dump(p, "OUT=%d ", msg->queue_msg_outdev); + } + + if (msg->ce_mask & QUEUE_MSG_ATTR_PHYSOUTDEV) { + if (link_cache) + nl_dump(p, "PHYSOUT=%s ", + rtnl_link_i2name(link_cache, + msg->queue_msg_physoutdev, + buf, sizeof(buf))); + else + nl_dump(p, "PHYSOUT=%d ", msg->queue_msg_physoutdev); + } + + if (msg->ce_mask & QUEUE_MSG_ATTR_HWADDR) { + int i; + + nl_dump(p, "MAC"); + for (i = 0; i < msg->queue_msg_hwaddr_len; i++) + nl_dump(p, "%c%02x", i?':':'=', + msg->queue_msg_hwaddr[i]); + nl_dump(p, " "); + } + + if (msg->ce_mask & QUEUE_MSG_ATTR_FAMILY) + nl_dump(p, "FAMILY=%s ", + nl_af2str(msg->queue_msg_family, buf, sizeof(buf))); + + if (msg->ce_mask & QUEUE_MSG_ATTR_HWPROTO) + nl_dump(p, "HWPROTO=%s ", + nl_ether_proto2str(ntohs(msg->queue_msg_hwproto), + buf, sizeof(buf))); + + if (msg->ce_mask & QUEUE_MSG_ATTR_HOOK) + nl_dump(p, "HOOK=%s ", + nfnl_inet_hook2str(msg->queue_msg_hook, + buf, sizeof(buf))); + + if (msg->ce_mask & QUEUE_MSG_ATTR_MARK) + nl_dump(p, "MARK=%d ", msg->queue_msg_mark); + + if (msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD) + nl_dump(p, "PAYLOADLEN=%d ", msg->queue_msg_payload_len); + + if (msg->ce_mask & QUEUE_MSG_ATTR_PACKETID) + nl_dump(p, "PACKETID=%u ", msg->queue_msg_packetid); + + if (msg->ce_mask & QUEUE_MSG_ATTR_VERDICT) + nl_dump(p, "VERDICT=%s ", + nfnl_verdict2str(msg->queue_msg_verdict, + buf, sizeof(buf))); + + nl_dump(p, "\n"); +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct nfnl_queue_msg *nfnl_queue_msg_alloc(void) +{ + return (struct nfnl_queue_msg *) nl_object_alloc(&queue_msg_obj_ops); +} + +void nfnl_queue_msg_get(struct nfnl_queue_msg *msg) +{ + nl_object_get((struct nl_object *) msg); +} + +void nfnl_queue_msg_put(struct nfnl_queue_msg *msg) +{ + nl_object_put((struct nl_object *) msg); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void nfnl_queue_msg_set_group(struct nfnl_queue_msg *msg, uint16_t group) +{ + msg->queue_msg_group = group; + msg->ce_mask |= QUEUE_MSG_ATTR_GROUP; +} + +int nfnl_queue_msg_test_group(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_GROUP); +} + +uint16_t nfnl_queue_msg_get_group(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_group; +} + +/** +* Set the protocol family +* @arg msg NF queue message +* @arg family AF_XXX address family example: AF_INET, AF_UNIX, etc +*/ +void nfnl_queue_msg_set_family(struct nfnl_queue_msg *msg, uint8_t family) +{ + msg->queue_msg_family = family; + msg->ce_mask |= QUEUE_MSG_ATTR_FAMILY; +} + +int nfnl_queue_msg_test_family(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_FAMILY); +} + +uint8_t nfnl_queue_msg_get_family(const struct nfnl_queue_msg *msg) +{ + if (msg->ce_mask & QUEUE_MSG_ATTR_FAMILY) + return msg->queue_msg_family; + else + return AF_UNSPEC; +} + +void nfnl_queue_msg_set_packetid(struct nfnl_queue_msg *msg, uint32_t packetid) +{ + msg->queue_msg_packetid = packetid; + msg->ce_mask |= QUEUE_MSG_ATTR_PACKETID; +} + +int nfnl_queue_msg_test_packetid(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_PACKETID); +} + +uint32_t nfnl_queue_msg_get_packetid(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_packetid; +} + +void nfnl_queue_msg_set_hwproto(struct nfnl_queue_msg *msg, uint16_t hwproto) +{ + msg->queue_msg_hwproto = hwproto; + msg->ce_mask |= QUEUE_MSG_ATTR_HWPROTO; +} + +int nfnl_queue_msg_test_hwproto(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_HWPROTO); +} + +uint16_t nfnl_queue_msg_get_hwproto(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_hwproto; +} + +void nfnl_queue_msg_set_hook(struct nfnl_queue_msg *msg, uint8_t hook) +{ + msg->queue_msg_hook = hook; + msg->ce_mask |= QUEUE_MSG_ATTR_HOOK; +} + +int nfnl_queue_msg_test_hook(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_HOOK); +} + +uint8_t nfnl_queue_msg_get_hook(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_hook; +} + +void nfnl_queue_msg_set_mark(struct nfnl_queue_msg *msg, uint32_t mark) +{ + msg->queue_msg_mark = mark; + msg->ce_mask |= QUEUE_MSG_ATTR_MARK; +} + +int nfnl_queue_msg_test_mark(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_MARK); +} + +uint32_t nfnl_queue_msg_get_mark(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_mark; +} + +void nfnl_queue_msg_set_timestamp(struct nfnl_queue_msg *msg, + struct timeval *tv) +{ + msg->queue_msg_timestamp.tv_sec = tv->tv_sec; + msg->queue_msg_timestamp.tv_usec = tv->tv_usec; + msg->ce_mask |= QUEUE_MSG_ATTR_TIMESTAMP; +} + +int nfnl_queue_msg_test_timestamp(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_TIMESTAMP); +} + +const struct timeval *nfnl_queue_msg_get_timestamp(const struct nfnl_queue_msg *msg) +{ + if (!(msg->ce_mask & QUEUE_MSG_ATTR_TIMESTAMP)) + return NULL; + return &msg->queue_msg_timestamp; +} + +void nfnl_queue_msg_set_indev(struct nfnl_queue_msg *msg, uint32_t indev) +{ + msg->queue_msg_indev = indev; + msg->ce_mask |= QUEUE_MSG_ATTR_INDEV; +} + +int nfnl_queue_msg_test_indev(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_INDEV); +} + +uint32_t nfnl_queue_msg_get_indev(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_indev; +} + +void nfnl_queue_msg_set_outdev(struct nfnl_queue_msg *msg, uint32_t outdev) +{ + msg->queue_msg_outdev = outdev; + msg->ce_mask |= QUEUE_MSG_ATTR_OUTDEV; +} + +int nfnl_queue_msg_test_outdev(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_OUTDEV); +} + +uint32_t nfnl_queue_msg_get_outdev(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_outdev; +} + +void nfnl_queue_msg_set_physindev(struct nfnl_queue_msg *msg, + uint32_t physindev) +{ + msg->queue_msg_physindev = physindev; + msg->ce_mask |= QUEUE_MSG_ATTR_PHYSINDEV; +} + +int nfnl_queue_msg_test_physindev(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_PHYSINDEV); +} + +uint32_t nfnl_queue_msg_get_physindev(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_physindev; +} + +void nfnl_queue_msg_set_physoutdev(struct nfnl_queue_msg *msg, + uint32_t physoutdev) +{ + msg->queue_msg_physoutdev = physoutdev; + msg->ce_mask |= QUEUE_MSG_ATTR_PHYSOUTDEV; +} + +int nfnl_queue_msg_test_physoutdev(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_PHYSOUTDEV); +} + +uint32_t nfnl_queue_msg_get_physoutdev(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_physoutdev; +} + +void nfnl_queue_msg_set_hwaddr(struct nfnl_queue_msg *msg, uint8_t *hwaddr, + int len) +{ + if (len > sizeof(msg->queue_msg_hwaddr)) + len = sizeof(msg->queue_msg_hwaddr); + + msg->queue_msg_hwaddr_len = len; + memcpy(msg->queue_msg_hwaddr, hwaddr, len); + msg->ce_mask |= QUEUE_MSG_ATTR_HWADDR; +} + +int nfnl_queue_msg_test_hwaddr(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_HWADDR); +} + +const uint8_t *nfnl_queue_msg_get_hwaddr(const struct nfnl_queue_msg *msg, + int *len) +{ + if (!(msg->ce_mask & QUEUE_MSG_ATTR_HWADDR)) { + *len = 0; + return NULL; + } + + *len = msg->queue_msg_hwaddr_len; + return msg->queue_msg_hwaddr; +} + +int nfnl_queue_msg_set_payload(struct nfnl_queue_msg *msg, uint8_t *payload, + int len) +{ + free(msg->queue_msg_payload); + msg->queue_msg_payload = malloc(len); + if (!msg->queue_msg_payload) + return -NLE_NOMEM; + + memcpy(msg->queue_msg_payload, payload, len); + msg->queue_msg_payload_len = len; + msg->ce_mask |= QUEUE_MSG_ATTR_PAYLOAD; + return 0; +} + +int nfnl_queue_msg_test_payload(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD); +} + +const void *nfnl_queue_msg_get_payload(const struct nfnl_queue_msg *msg, int *len) +{ + if (!(msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD)) { + *len = 0; + return NULL; + } + + *len = msg->queue_msg_payload_len; + return msg->queue_msg_payload; +} + +/** +* Return the number of items matching a filter in the cache +* @arg msg queue msg +* @arg verdict NF_DROP, NF_ACCEPT, NF_REPEAT, etc +*/ +void nfnl_queue_msg_set_verdict(struct nfnl_queue_msg *msg, + unsigned int verdict) +{ + msg->queue_msg_verdict = verdict; + msg->ce_mask |= QUEUE_MSG_ATTR_VERDICT; +} + +int nfnl_queue_msg_test_verdict(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_VERDICT); +} + +unsigned int nfnl_queue_msg_get_verdict(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_verdict; +} + +static const struct trans_tbl nfnl_queue_msg_attrs[] = { + __ADD(QUEUE_MSG_ATTR_GROUP, group) + __ADD(QUEUE_MSG_ATTR_FAMILY, family) + __ADD(QUEUE_MSG_ATTR_PACKETID, packetid) + __ADD(QUEUE_MSG_ATTR_HWPROTO, hwproto) + __ADD(QUEUE_MSG_ATTR_HOOK, hook) + __ADD(QUEUE_MSG_ATTR_MARK, mark) + __ADD(QUEUE_MSG_ATTR_TIMESTAMP, timestamp) + __ADD(QUEUE_MSG_ATTR_INDEV, indev) + __ADD(QUEUE_MSG_ATTR_OUTDEV, outdev) + __ADD(QUEUE_MSG_ATTR_PHYSINDEV, physindev) + __ADD(QUEUE_MSG_ATTR_PHYSOUTDEV, physoutdev) + __ADD(QUEUE_MSG_ATTR_HWADDR, hwaddr) + __ADD(QUEUE_MSG_ATTR_PAYLOAD, payload) + __ADD(QUEUE_MSG_ATTR_VERDICT, verdict) +}; + +static char *nfnl_queue_msg_attrs2str(int attrs, char *buf, size_t len) +{ + return __flags2str(attrs, buf, len, nfnl_queue_msg_attrs, + ARRAY_SIZE(nfnl_queue_msg_attrs)); +} + +/** @} */ + +struct nl_object_ops queue_msg_obj_ops = { + .oo_name = "netfilter/queuemsg", + .oo_size = sizeof(struct nfnl_queue_msg), + .oo_free_data = nfnl_queue_msg_free_data, + .oo_clone = nfnl_queue_msg_clone, + .oo_dump = { + [NL_DUMP_LINE] = nfnl_queue_msg_dump, + [NL_DUMP_DETAILS] = nfnl_queue_msg_dump, + [NL_DUMP_STATS] = nfnl_queue_msg_dump, + }, + .oo_attrs2str = nfnl_queue_msg_attrs2str, +}; + +/** @} */ diff --git a/libnetwork/libnl3/lib/netfilter/queue_obj.c b/libnetwork/libnl3/lib/netfilter/queue_obj.c new file mode 100644 index 0000000..05a9cb8 --- /dev/null +++ b/libnetwork/libnl3/lib/netfilter/queue_obj.c @@ -0,0 +1,215 @@ +/* + * lib/netfilter/queue_obj.c Netfilter Queue + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2007, 2008 Patrick McHardy + */ + +/** + * @ingroup nfnl + * @defgroup queue Queue + * @brief + * @{ + */ + +#include +#include +#include + +/** @cond SKIP */ +#define QUEUE_ATTR_GROUP (1UL << 0) +#define QUEUE_ATTR_MAXLEN (1UL << 1) +#define QUEUE_ATTR_COPY_MODE (1UL << 2) +#define QUEUE_ATTR_COPY_RANGE (1UL << 3) +/** @endcond */ + + +static void nfnl_queue_dump(struct nl_object *a, struct nl_dump_params *p) +{ + struct nfnl_queue *queue = (struct nfnl_queue *) a; + char buf[64]; + + nl_new_line(p); + + if (queue->ce_mask & QUEUE_ATTR_GROUP) + nl_dump(p, "group=%u ", queue->queue_group); + + if (queue->ce_mask & QUEUE_ATTR_MAXLEN) + nl_dump(p, "maxlen=%u ", queue->queue_maxlen); + + if (queue->ce_mask & QUEUE_ATTR_COPY_MODE) + nl_dump(p, "copy_mode=%s ", + nfnl_queue_copy_mode2str(queue->queue_copy_mode, + buf, sizeof(buf))); + + if (queue->ce_mask & QUEUE_ATTR_COPY_RANGE) + nl_dump(p, "copy_range=%u ", queue->queue_copy_range); + + nl_dump(p, "\n"); +} + +static const struct trans_tbl copy_modes[] = { + __ADD(NFNL_QUEUE_COPY_NONE, none) + __ADD(NFNL_QUEUE_COPY_META, meta) + __ADD(NFNL_QUEUE_COPY_PACKET, packet) +}; + +char *nfnl_queue_copy_mode2str(enum nfnl_queue_copy_mode copy_mode, char *buf, + size_t len) +{ + return __type2str(copy_mode, buf, len, copy_modes, + ARRAY_SIZE(copy_modes)); +} + +enum nfnl_queue_copy_mode nfnl_queue_str2copy_mode(const char *name) +{ + return __str2type(name, copy_modes, ARRAY_SIZE(copy_modes)); +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct nfnl_queue *nfnl_queue_alloc(void) +{ + return (struct nfnl_queue *) nl_object_alloc(&queue_obj_ops); +} + +void nfnl_queue_get(struct nfnl_queue *queue) +{ + nl_object_get((struct nl_object *) queue); +} + +void nfnl_queue_put(struct nfnl_queue *queue) +{ + nl_object_put((struct nl_object *) queue); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void nfnl_queue_set_group(struct nfnl_queue *queue, uint16_t group) +{ + queue->queue_group = group; + queue->ce_mask |= QUEUE_ATTR_GROUP; +} + +int nfnl_queue_test_group(const struct nfnl_queue *queue) +{ + return !!(queue->ce_mask & QUEUE_ATTR_GROUP); +} + +uint16_t nfnl_queue_get_group(const struct nfnl_queue *queue) +{ + return queue->queue_group; +} + +void nfnl_queue_set_maxlen(struct nfnl_queue *queue, uint32_t maxlen) +{ + queue->queue_maxlen = maxlen; + queue->ce_mask |= QUEUE_ATTR_MAXLEN; +} + +int nfnl_queue_test_maxlen(const struct nfnl_queue *queue) +{ + return !!(queue->ce_mask & QUEUE_ATTR_MAXLEN); +} + +uint32_t nfnl_queue_get_maxlen(const struct nfnl_queue *queue) +{ + return queue->queue_maxlen; +} + +void nfnl_queue_set_copy_mode(struct nfnl_queue *queue, enum nfnl_queue_copy_mode mode) +{ + queue->queue_copy_mode = mode; + queue->ce_mask |= QUEUE_ATTR_COPY_MODE; +} + +int nfnl_queue_test_copy_mode(const struct nfnl_queue *queue) +{ + return !!(queue->ce_mask & QUEUE_ATTR_COPY_MODE); +} + +enum nfnl_queue_copy_mode nfnl_queue_get_copy_mode(const struct nfnl_queue *queue) +{ + return queue->queue_copy_mode; +} + +void nfnl_queue_set_copy_range(struct nfnl_queue *queue, uint32_t copy_range) +{ + queue->queue_copy_range = copy_range; + queue->ce_mask |= QUEUE_ATTR_COPY_RANGE; +} + +int nfnl_queue_test_copy_range(const struct nfnl_queue *queue) +{ + return !!(queue->ce_mask & QUEUE_ATTR_COPY_RANGE); +} + +uint32_t nfnl_queue_get_copy_range(const struct nfnl_queue *queue) +{ + return queue->queue_copy_range; +} + +static int nfnl_queue_compare(struct nl_object *_a, struct nl_object *_b, + uint32_t attrs, int flags) +{ + struct nfnl_queue *a = (struct nfnl_queue *) _a; + struct nfnl_queue *b = (struct nfnl_queue *) _b; + int diff = 0; + +#define NFNL_QUEUE_DIFF(ATTR, EXPR) \ + ATTR_DIFF(attrs, QUEUE_ATTR_##ATTR, a, b, EXPR) +#define NFNL_QUEUE_DIFF_VAL(ATTR, FIELD) \ + NFNL_QUEUE_DIFF(ATTR, a->FIELD != b->FIELD) + + diff |= NFNL_QUEUE_DIFF_VAL(GROUP, queue_group); + diff |= NFNL_QUEUE_DIFF_VAL(MAXLEN, queue_maxlen); + diff |= NFNL_QUEUE_DIFF_VAL(COPY_MODE, queue_copy_mode); + diff |= NFNL_QUEUE_DIFF_VAL(COPY_RANGE, queue_copy_range); + +#undef NFNL_QUEUE_DIFF +#undef NFNL_QUEUE_DIFF_VAL + + return diff; +} + +static const struct trans_tbl nfnl_queue_attrs[] = { + __ADD(QUEUE_ATTR_GROUP, group) + __ADD(QUEUE_ATTR_MAXLEN, maxlen) + __ADD(QUEUE_ATTR_COPY_MODE, copy_mode) + __ADD(QUEUE_ATTR_COPY_RANGE, copy_range) +}; + +static char *nfnl_queue_attrs2str(int attrs, char *buf, size_t len) +{ + return __flags2str(attrs, buf, len, nfnl_queue_attrs, + ARRAY_SIZE(nfnl_queue_attrs)); +} + +/** @} */ + +struct nl_object_ops queue_obj_ops = { + .oo_name = "netfilter/queue", + .oo_size = sizeof(struct nfnl_queue), + .oo_dump = { + [NL_DUMP_LINE] = nfnl_queue_dump, + [NL_DUMP_DETAILS] = nfnl_queue_dump, + [NL_DUMP_STATS] = nfnl_queue_dump, + }, + .oo_compare = nfnl_queue_compare, + .oo_attrs2str = nfnl_queue_attrs2str, + .oo_id_attrs = QUEUE_ATTR_GROUP, +}; + +/** @} */ diff --git a/libnetwork/libnl3/lib/nl.c b/libnetwork/libnl3/lib/nl.c new file mode 100644 index 0000000..bcf89da --- /dev/null +++ b/libnetwork/libnl3/lib/nl.c @@ -0,0 +1,896 @@ +/* + * lib/nl.c Core Netlink Interface + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @defgroup core Core + * + * @details + * @par 1) Connecting the socket + * @code + * // Bind and connect the socket to a protocol, NETLINK_ROUTE in this example. + * nl_connect(sk, NETLINK_ROUTE); + * @endcode + * + * @par 2) Sending data + * @code + * // The most rudimentary method is to use nl_sendto() simply pushing + * // a piece of data to the other netlink peer. This method is not + * // recommended. + * const char buf[] = { 0x01, 0x02, 0x03, 0x04 }; + * nl_sendto(sk, buf, sizeof(buf)); + * + * // A more comfortable interface is nl_send() taking a pointer to + * // a netlink message. + * struct nl_msg *msg = my_msg_builder(); + * nl_send(sk, nlmsg_hdr(msg)); + * + * // nl_sendmsg() provides additional control over the sendmsg() message + * // header in order to allow more specific addressing of multiple peers etc. + * struct msghdr hdr = { ... }; + * nl_sendmsg(sk, nlmsg_hdr(msg), &hdr); + * + * // You're probably too lazy to fill out the netlink pid, sequence number + * // and message flags all the time. nl_send_auto_complete() automatically + * // extends your message header as needed with an appropriate sequence + * // number, the netlink pid stored in the netlink socket and the message + * // flags NLM_F_REQUEST and NLM_F_ACK (if not disabled in the socket) + * nl_send_auto_complete(sk, nlmsg_hdr(msg)); + * + * // Simple protocols don't require the complex message construction interface + * // and may favour nl_send_simple() to easly send a bunch of payload + * // encapsulated in a netlink message header. + * nl_send_simple(sk, MY_MSG_TYPE, 0, buf, sizeof(buf)); + * @endcode + * + * @par 3) Receiving data + * @code + * // nl_recv() receives a single message allocating a buffer for the message + * // content and gives back the pointer to you. + * struct sockaddr_nl peer; + * unsigned char *msg; + * nl_recv(sk, &peer, &msg); + * + * // nl_recvmsgs() receives a bunch of messages until the callback system + * // orders it to state, usually after receving a compolete multi part + * // message series. + * nl_recvmsgs(sk, my_callback_configuration); + * + * // nl_recvmsgs_default() acts just like nl_recvmsg() but uses the callback + * // configuration stored in the socket. + * nl_recvmsgs_default(sk); + * + * // In case you want to wait for the ACK to be recieved that you requested + * // with your latest message, you can call nl_wait_for_ack() + * nl_wait_for_ack(sk); + * @endcode + * + * @par 4) Closing + * @code + * // Close the socket first to release kernel memory + * nl_close(sk); + * @endcode + * + * @{ + */ + +#include +#include +#include +#include +#include +#include + +/** + * @name Connection Management + * @{ + */ + +/** + * Create and connect netlink socket. + * @arg sk Netlink socket. + * @arg protocol Netlink protocol to use. + * + * Creates a netlink socket using the specified protocol, binds the socket + * and issues a connection attempt. + * + * @note SOCK_CLOEXEC is set on the socket if available. + * + * @return 0 on success or a negative error code. + */ +int nl_connect(struct nl_sock *sk, int protocol) +{ + int err, flags = 0; + socklen_t addrlen; + +#ifdef SOCK_CLOEXEC + flags |= SOCK_CLOEXEC; +#endif + + sk->s_fd = socket(AF_NETLINK, SOCK_RAW | flags, protocol); + if (sk->s_fd < 0) { + err = -nl_syserr2nlerr(errno); + goto errout; + } + + if (!(sk->s_flags & NL_SOCK_BUFSIZE_SET)) { + err = nl_socket_set_buffer_size(sk, 0, 0); + if (err < 0) + goto errout; + } + + err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local, + sizeof(sk->s_local)); + if (err < 0) { + err = -nl_syserr2nlerr(errno); + goto errout; + } + + addrlen = sizeof(sk->s_local); + err = getsockname(sk->s_fd, (struct sockaddr *) &sk->s_local, + &addrlen); + if (err < 0) { + err = -nl_syserr2nlerr(errno); + goto errout; + } + + if (addrlen != sizeof(sk->s_local)) { + err = -NLE_NOADDR; + goto errout; + } + + if (sk->s_local.nl_family != AF_NETLINK) { + err = -NLE_AF_NOSUPPORT; + goto errout; + } + + sk->s_proto = protocol; + + return 0; +errout: + close(sk->s_fd); + sk->s_fd = -1; + + return err; +} + +/** + * Close/Disconnect netlink socket. + * @arg sk Netlink socket. + */ +void nl_close(struct nl_sock *sk) +{ + if (sk->s_fd >= 0) { + close(sk->s_fd); + sk->s_fd = -1; + } + + sk->s_proto = 0; +} + +/** @} */ + +/** + * @name Send + * @{ + */ + +/** + * Send raw data over netlink socket. + * @arg sk Netlink socket. + * @arg buf Data buffer. + * @arg size Size of data buffer. + * @return Number of characters written on success or a negative error code. + */ +int nl_sendto(struct nl_sock *sk, void *buf, size_t size) +{ + int ret; + + ret = sendto(sk->s_fd, buf, size, 0, (struct sockaddr *) + &sk->s_peer, sizeof(sk->s_peer)); + if (ret < 0) + return -nl_syserr2nlerr(errno); + + return ret; +} + +/** + * Send netlink message with control over sendmsg() message header. + * @arg sk Netlink socket. + * @arg msg Netlink message to be sent. + * @arg hdr Sendmsg() message header. + * @return Number of characters sent on sucess or a negative error code. + */ +int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr) +{ + struct nl_cb *cb; + int ret; + + nlmsg_set_src(msg, &sk->s_local); + + cb = sk->s_cb; + if (cb->cb_set[NL_CB_MSG_OUT]) + if ((ret = nl_cb_call(cb, NL_CB_MSG_OUT, msg)) != NL_OK) + return ret; + + ret = sendmsg(sk->s_fd, hdr, 0); + if (ret < 0) + return -nl_syserr2nlerr(errno); + + NL_DBG(4, "sent %d bytes\n", ret); + return ret; +} + + +/** + * Send netlink message. + * @arg sk Netlink socket. + * @arg msg Netlink message to be sent. + * @arg iov iovec to be sent. + * @arg iovlen number of struct iovec to be sent. + * @see nl_sendmsg() + * @return Number of characters sent on success or a negative error code. + */ +int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen) +{ + struct sockaddr_nl *dst; + struct ucred *creds; + struct msghdr hdr = { + .msg_name = (void *) &sk->s_peer, + .msg_namelen = sizeof(struct sockaddr_nl), + .msg_iov = iov, + .msg_iovlen = iovlen, + }; + + /* Overwrite destination if specified in the message itself, defaults + * to the peer address of the socket. + */ + dst = nlmsg_get_dst(msg); + if (dst->nl_family == AF_NETLINK) + hdr.msg_name = dst; + + /* Add credentials if present. */ + creds = nlmsg_get_creds(msg); + if (creds != NULL) { + char buf[CMSG_SPACE(sizeof(struct ucred))]; + struct cmsghdr *cmsg; + + hdr.msg_control = buf; + hdr.msg_controllen = sizeof(buf); + + cmsg = CMSG_FIRSTHDR(&hdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_CREDENTIALS; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); + memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred)); + } + + return nl_sendmsg(sk, msg, &hdr); +} + + + +/** +* Send netlink message. +* @arg sk Netlink socket. +* @arg msg Netlink message to be sent. +* @see nl_sendmsg() +* @return Number of characters sent on success or a negative error code. +*/ +int nl_send(struct nl_sock *sk, struct nl_msg *msg) +{ + struct iovec iov = { + .iov_base = (void *) nlmsg_hdr(msg), + .iov_len = nlmsg_hdr(msg)->nlmsg_len, + }; + + return nl_send_iovec(sk, msg, &iov, 1); +} + +void nl_complete_msg(struct nl_sock *sk, struct nl_msg *msg) +{ + struct nlmsghdr *nlh; + + nlh = nlmsg_hdr(msg); + if (nlh->nlmsg_pid == 0) + nlh->nlmsg_pid = sk->s_local.nl_pid; + + if (nlh->nlmsg_seq == 0) + nlh->nlmsg_seq = sk->s_seq_next++; + + if (msg->nm_protocol == -1) + msg->nm_protocol = sk->s_proto; + + nlh->nlmsg_flags |= NLM_F_REQUEST; + + if (!(sk->s_flags & NL_NO_AUTO_ACK)) + nlh->nlmsg_flags |= NLM_F_ACK; +} + +void nl_auto_complete(struct nl_sock *sk, struct nl_msg *msg) +{ + nl_complete_msg(sk, msg); +} + +/** + * Automatically complete and send a netlink message + * @arg sk Netlink socket. + * @arg msg Netlink message to be sent. + * + * This function takes a netlink message and passes it on to + * nl_auto_complete() for completion. + * + * Checks the netlink message \c nlh for completness and extends it + * as required before sending it out. Checked fields include pid, + * sequence nr, and flags. + * + * @see nl_send() + * @return Number of characters sent or a negative error code. + */ +int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg) +{ + struct nl_cb *cb = sk->s_cb; + + nl_complete_msg(sk, msg); + + if (cb->cb_send_ow) + return cb->cb_send_ow(sk, msg); + else + return nl_send(sk, msg); +} + +int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg) +{ + return nl_send_auto(sk, msg); +} + +/** + * Send netlink message and wait for response (sync request-response) + * @arg sk Netlink socket + * @arg msg Netlink message to be sent + * + * This function takes a netlink message and sends it using nl_send_auto(). + * It will then wait for the response (ACK or error message) to be + * received. Threfore this function will block until the operation has + * been completed. + * + * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause + * this function to return immediately after sending. In this case, + * it is the responsibility of the caller to handle any eventual + * error messages returned. + * + * @see nl_send_auto(). + * + * @return 0 on success or a negative error code. + */ +int nl_send_sync(struct nl_sock *sk, struct nl_msg *msg) +{ + int err; + + err = nl_send_auto(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +/** + * Send simple netlink message using nl_send_auto_complete() + * @arg sk Netlink socket. + * @arg type Netlink message type. + * @arg flags Netlink message flags. + * @arg buf Data buffer. + * @arg size Size of data buffer. + * + * Builds a netlink message with the specified type and flags and + * appends the specified data as payload to the message. + * + * @see nl_send_auto_complete() + * @return Number of characters sent on success or a negative error code. + */ +int nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf, + size_t size) +{ + int err; + struct nl_msg *msg; + + msg = nlmsg_alloc_simple(type, flags); + if (!msg) + return -NLE_NOMEM; + + if (buf && size) { + err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO); + if (err < 0) + goto errout; + } + + + err = nl_send_auto_complete(sk, msg); +errout: + nlmsg_free(msg); + + return err; +} + +/** @} */ + +/** + * @name Receive + * @{ + */ + +/** + * Receive data from netlink socket + * @arg sk Netlink socket. + * @arg nla Destination pointer for peer's netlink address. + * @arg buf Destination pointer for message content. + * @arg creds Destination pointer for credentials. + * + * Receives a netlink message, allocates a buffer in \c *buf and + * stores the message content. The peer's netlink address is stored + * in \c *nla. The caller is responsible for freeing the buffer allocated + * in \c *buf if a positive value is returned. Interrupted system calls + * are handled by repeating the read. The input buffer size is determined + * by peeking before the actual read is done. + * + * A non-blocking sockets causes the function to return immediately with + * a return value of 0 if no data is available. + * + * @return Number of octets read, 0 on EOF or a negative error code. + */ +int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, + unsigned char **buf, struct ucred **creds) +{ + int n; + int flags = 0; + static int page_size = 0; + struct iovec iov; + struct msghdr msg = { + .msg_name = (void *) nla, + .msg_namelen = sizeof(struct sockaddr_nl), + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = NULL, + .msg_controllen = 0, + .msg_flags = 0, + }; + struct cmsghdr *cmsg; + + memset(nla, 0, sizeof(*nla)); + + if (sk->s_flags & NL_MSG_PEEK) + flags |= MSG_PEEK; + + if (page_size == 0) + page_size = getpagesize(); + + iov.iov_len = page_size; + iov.iov_base = *buf = malloc(iov.iov_len); + + if (sk->s_flags & NL_SOCK_PASSCRED) { + msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred)); + msg.msg_control = calloc(1, msg.msg_controllen); + } +retry: + + n = recvmsg(sk->s_fd, &msg, flags); + if (!n) + goto abort; + else if (n < 0) { + if (errno == EINTR) { + NL_DBG(3, "recvmsg() returned EINTR, retrying\n"); + goto retry; + } else if (errno == EAGAIN) { + NL_DBG(3, "recvmsg() returned EAGAIN, aborting\n"); + goto abort; + } else { + free(msg.msg_control); + free(*buf); + return -nl_syserr2nlerr(errno); + } + } + + if (iov.iov_len < n || + msg.msg_flags & MSG_TRUNC) { + /* Provided buffer is not long enough, enlarge it + * and try again. */ + iov.iov_len *= 2; + iov.iov_base = *buf = realloc(*buf, iov.iov_len); + goto retry; + } else if (msg.msg_flags & MSG_CTRUNC) { + msg.msg_controllen *= 2; + msg.msg_control = realloc(msg.msg_control, msg.msg_controllen); + goto retry; + } else if (flags != 0) { + /* Buffer is big enough, do the actual reading */ + flags = 0; + goto retry; + } + + if (msg.msg_namelen != sizeof(struct sockaddr_nl)) { + free(msg.msg_control); + free(*buf); + return -NLE_NOADDR; + } + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS) { + if (creds) { + *creds = calloc(1, sizeof(struct ucred)); + memcpy(*creds, CMSG_DATA(cmsg), sizeof(struct ucred)); + } + break; + } + } + + free(msg.msg_control); + return n; + +abort: + free(msg.msg_control); + free(*buf); + return 0; +} + +#define NL_CB_CALL(cb, type, msg) \ +do { \ + err = nl_cb_call(cb, type, msg); \ + switch (err) { \ + case NL_OK: \ + err = 0; \ + break; \ + case NL_SKIP: \ + goto skip; \ + case NL_STOP: \ + goto stop; \ + default: \ + goto out; \ + } \ +} while (0) + +static int recvmsgs(struct nl_sock *sk, struct nl_cb *cb) +{ + int n, err = 0, multipart = 0, interrupted = 0; + unsigned char *buf = NULL; + struct nlmsghdr *hdr; + struct sockaddr_nl nla = {0}; + struct nl_msg *msg = NULL; + struct ucred *creds = NULL; + +continue_reading: + NL_DBG(3, "Attempting to read from %p\n", sk); + if (cb->cb_recv_ow) + n = cb->cb_recv_ow(sk, &nla, &buf, &creds); + else + n = nl_recv(sk, &nla, &buf, &creds); + + if (n <= 0) + return n; + + NL_DBG(3, "recvmsgs(%p): Read %d bytes\n", sk, n); + + hdr = (struct nlmsghdr *) buf; + while (nlmsg_ok(hdr, n)) { + NL_DBG(3, "recvmsgs(%p): Processing valid message...\n", sk); + + nlmsg_free(msg); + msg = nlmsg_convert(hdr); + if (!msg) { + err = -NLE_NOMEM; + goto out; + } + + nlmsg_set_proto(msg, sk->s_proto); + nlmsg_set_src(msg, &nla); + if (creds) + nlmsg_set_creds(msg, creds); + + /* Raw callback is the first, it gives the most control + * to the user and he can do his very own parsing. */ + if (cb->cb_set[NL_CB_MSG_IN]) + NL_CB_CALL(cb, NL_CB_MSG_IN, msg); + + /* Sequence number checking. The check may be done by + * the user, otherwise a very simple check is applied + * enforcing strict ordering */ + if (cb->cb_set[NL_CB_SEQ_CHECK]) { + NL_CB_CALL(cb, NL_CB_SEQ_CHECK, msg); + + /* Only do sequence checking if auto-ack mode is enabled */ + } else if (!(sk->s_flags & NL_NO_AUTO_ACK)) { + if (hdr->nlmsg_seq != sk->s_seq_expect) { + if (cb->cb_set[NL_CB_INVALID]) + NL_CB_CALL(cb, NL_CB_INVALID, msg); + else { + err = -NLE_SEQ_MISMATCH; + goto out; + } + } + } + + if (hdr->nlmsg_type == NLMSG_DONE || + hdr->nlmsg_type == NLMSG_ERROR || + hdr->nlmsg_type == NLMSG_NOOP || + hdr->nlmsg_type == NLMSG_OVERRUN) { + /* We can't check for !NLM_F_MULTI since some netlink + * users in the kernel are broken. */ + sk->s_seq_expect++; + NL_DBG(3, "recvmsgs(%p): Increased expected " \ + "sequence number to %d\n", + sk, sk->s_seq_expect); + } + + if (hdr->nlmsg_flags & NLM_F_MULTI) + multipart = 1; + + if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) { + if (cb->cb_set[NL_CB_DUMP_INTR]) + NL_CB_CALL(cb, NL_CB_DUMP_INTR, msg); + else { + /* + * We have to continue reading to clear + * all messages until a NLMSG_DONE is + * received and report the inconsistency. + */ + interrupted = 1; + } + } + + /* Other side wishes to see an ack for this message */ + if (hdr->nlmsg_flags & NLM_F_ACK) { + if (cb->cb_set[NL_CB_SEND_ACK]) + NL_CB_CALL(cb, NL_CB_SEND_ACK, msg); + else { + /* FIXME: implement */ + } + } + + /* messages terminates a multpart message, this is + * usually the end of a message and therefore we slip + * out of the loop by default. the user may overrule + * this action by skipping this packet. */ + if (hdr->nlmsg_type == NLMSG_DONE) { + multipart = 0; + if (cb->cb_set[NL_CB_FINISH]) + NL_CB_CALL(cb, NL_CB_FINISH, msg); + } + + /* Message to be ignored, the default action is to + * skip this message if no callback is specified. The + * user may overrule this action by returning + * NL_PROCEED. */ + else if (hdr->nlmsg_type == NLMSG_NOOP) { + if (cb->cb_set[NL_CB_SKIPPED]) + NL_CB_CALL(cb, NL_CB_SKIPPED, msg); + else + goto skip; + } + + /* Data got lost, report back to user. The default action is to + * quit parsing. The user may overrule this action by retuning + * NL_SKIP or NL_PROCEED (dangerous) */ + else if (hdr->nlmsg_type == NLMSG_OVERRUN) { + if (cb->cb_set[NL_CB_OVERRUN]) + NL_CB_CALL(cb, NL_CB_OVERRUN, msg); + else { + err = -NLE_MSG_OVERFLOW; + goto out; + } + } + + /* Message carries a nlmsgerr */ + else if (hdr->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *e = nlmsg_data(hdr); + + if (hdr->nlmsg_len < nlmsg_size(sizeof(*e))) { + /* Truncated error message, the default action + * is to stop parsing. The user may overrule + * this action by returning NL_SKIP or + * NL_PROCEED (dangerous) */ + if (cb->cb_set[NL_CB_INVALID]) + NL_CB_CALL(cb, NL_CB_INVALID, msg); + else { + err = -NLE_MSG_TRUNC; + goto out; + } + } else if (e->error) { + /* Error message reported back from kernel. */ + if (cb->cb_err) { + err = cb->cb_err(&nla, e, + cb->cb_err_arg); + if (err < 0) + goto out; + else if (err == NL_SKIP) + goto skip; + else if (err == NL_STOP) { + err = -nl_syserr2nlerr(e->error); + goto out; + } + } else { + err = -nl_syserr2nlerr(e->error); + goto out; + } + } else if (cb->cb_set[NL_CB_ACK]) + NL_CB_CALL(cb, NL_CB_ACK, msg); + } else { + /* Valid message (not checking for MULTIPART bit to + * get along with broken kernels. NL_SKIP has no + * effect on this. */ + if (cb->cb_set[NL_CB_VALID]) + NL_CB_CALL(cb, NL_CB_VALID, msg); + } +skip: + err = 0; + hdr = nlmsg_next(hdr, &n); + } + + nlmsg_free(msg); + free(buf); + free(creds); + buf = NULL; + msg = NULL; + creds = NULL; + + if (multipart) { + /* Multipart message not yet complete, continue reading */ + goto continue_reading; + } +stop: + err = 0; +out: + nlmsg_free(msg); + free(buf); + free(creds); + + if (interrupted) + err = -NLE_DUMP_INTR; + + return err; +} + +/** + * Receive a set of messages from a netlink socket. + * @arg sk Netlink socket. + * @arg cb set of callbacks to control behaviour. + * + * Repeatedly calls nl_recv() or the respective replacement if provided + * by the application (see nl_cb_overwrite_recv()) and parses the + * received data as netlink messages. Stops reading if one of the + * callbacks returns NL_STOP or nl_recv returns either 0 or a negative error code. + * + * A non-blocking sockets causes the function to return immediately if + * no data is available. + * + * @return 0 on success or a negative error code from nl_recv(). + */ +int nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb) +{ + if (cb->cb_recvmsgs_ow) + return cb->cb_recvmsgs_ow(sk, cb); + else + return recvmsgs(sk, cb); +} + +/** + * Receive a set of message from a netlink socket using handlers in nl_sock. + * @arg sk Netlink socket. + * + * Calls nl_recvmsgs() with the handlers configured in the netlink socket. + */ +int nl_recvmsgs_default(struct nl_sock *sk) +{ + return nl_recvmsgs(sk, sk->s_cb); + +} + +static int ack_wait_handler(struct nl_msg *msg, void *arg) +{ + return NL_STOP; +} + +/** + * Wait for ACK. + * @arg sk Netlink socket. + * @pre The netlink socket must be in blocking state. + * + * Waits until an ACK is received for the latest not yet acknowledged + * netlink message. + */ +int nl_wait_for_ack(struct nl_sock *sk) +{ + int err; + struct nl_cb *cb; + + cb = nl_cb_clone(sk->s_cb); + if (cb == NULL) + return -NLE_NOMEM; + + nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, NULL); + err = nl_recvmsgs(sk, cb); + nl_cb_put(cb); + + return err; +} + +/** @cond SKIP */ +struct pickup_param +{ + int (*parser)(struct nl_cache_ops *, struct sockaddr_nl *, + struct nlmsghdr *, struct nl_parser_param *); + struct nl_object *result; +}; + +static int __store_answer(struct nl_object *obj, struct nl_parser_param *p) +{ + struct pickup_param *pp = p->pp_arg; + /* + * the parser will put() the object at the end, expecting the cache + * to take the reference. + */ + nl_object_get(obj); + pp->result = obj; + + return 0; +} + +static int __pickup_answer(struct nl_msg *msg, void *arg) +{ + struct pickup_param *pp = arg; + struct nl_parser_param parse_arg = { + .pp_cb = __store_answer, + .pp_arg = pp, + }; + + return pp->parser(NULL, &msg->nm_src, msg->nm_nlh, &parse_arg); +} + +/** @endcond */ + +/** + * Pickup netlink answer, parse is and return object + * @arg sk Netlink socket + * @arg parser Parser function to parse answer + * @arg result Result pointer to return parsed object + * + * @return 0 on success or a negative error code. + */ +int nl_pickup(struct nl_sock *sk, + int (*parser)(struct nl_cache_ops *, struct sockaddr_nl *, + struct nlmsghdr *, struct nl_parser_param *), + struct nl_object **result) +{ + struct nl_cb *cb; + int err; + struct pickup_param pp = { + .parser = parser, + }; + + cb = nl_cb_clone(sk->s_cb); + if (cb == NULL) + return -NLE_NOMEM; + + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, __pickup_answer, &pp); + + err = nl_recvmsgs(sk, cb); + if (err < 0) + goto errout; + + *result = pp.result; +errout: + nl_cb_put(cb); + + return err; +} + +/** @} */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/object.c b/libnetwork/libnl3/lib/object.c new file mode 100644 index 0000000..3bf02ea --- /dev/null +++ b/libnetwork/libnl3/lib/object.c @@ -0,0 +1,395 @@ +/* + * lib/object.c Generic Cacheable Object + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup cache + * @defgroup object Object + * @{ + */ + +#include +#include +#include +#include +#include + +static inline struct nl_object_ops *obj_ops(struct nl_object *obj) +{ + if (!obj->ce_ops) + BUG(); + + return obj->ce_ops; +} + +/** + * @name Object Creation/Deletion + * @{ + */ + +/** + * Allocate a new object of kind specified by the operations handle + * @arg ops cache operations handle + * @return The new object or NULL + */ +struct nl_object *nl_object_alloc(struct nl_object_ops *ops) +{ + struct nl_object *new; + + if (ops->oo_size < sizeof(*new)) + BUG(); + + new = calloc(1, ops->oo_size); + if (!new) + return NULL; + + new->ce_refcnt = 1; + nl_init_list_head(&new->ce_list); + + new->ce_ops = ops; + if (ops->oo_constructor) + ops->oo_constructor(new); + + NL_DBG(4, "Allocated new object %p\n", new); + + return new; +} + +/** + * Allocate new object of kind specified by the name + * @arg kind name of object type + * @arg result Result pointer + * + * @return 0 on success or a negative error code. + */ +int nl_object_alloc_name(const char *kind, struct nl_object **result) +{ + struct nl_cache_ops *ops; + + ops = nl_cache_ops_lookup(kind); + if (!ops) + return -NLE_OPNOTSUPP; + + if (!(*result = nl_object_alloc(ops->co_obj_ops))) + return -NLE_NOMEM; + + return 0; +} + +struct nl_derived_object { + NLHDR_COMMON + char data; +}; + +/** + * Allocate a new object and copy all data from an existing object + * @arg obj object to inherite data from + * @return The new object or NULL. + */ +struct nl_object *nl_object_clone(struct nl_object *obj) +{ + struct nl_object *new; + struct nl_object_ops *ops = obj_ops(obj); + int doff = offsetof(struct nl_derived_object, data); + int size; + + new = nl_object_alloc(ops); + if (!new) + return NULL; + + size = ops->oo_size - doff; + if (size < 0) + BUG(); + + new->ce_ops = obj->ce_ops; + new->ce_msgtype = obj->ce_msgtype; + new->ce_mask = obj->ce_mask; + + if (size) + memcpy((void *)new + doff, (void *)obj + doff, size); + + if (ops->oo_clone) { + if (ops->oo_clone(new, obj) < 0) { + nl_object_free(new); + return NULL; + } + } else if (size && ops->oo_free_data) + BUG(); + + return new; +} + +/** + * Free a cacheable object + * @arg obj object to free + * + * @return 0 or a negative error code. + */ +void nl_object_free(struct nl_object *obj) +{ + struct nl_object_ops *ops = obj_ops(obj); + + if (obj->ce_refcnt > 0) + NL_DBG(1, "Warning: Freeing object in use...\n"); + + if (obj->ce_cache) + nl_cache_remove(obj); + + if (ops->oo_free_data) + ops->oo_free_data(obj); + + free(obj); + + NL_DBG(4, "Freed object %p\n", obj); +} + +/** @} */ + +/** + * @name Reference Management + * @{ + */ + +/** + * Acquire a reference on a object + * @arg obj object to acquire reference from + */ +void nl_object_get(struct nl_object *obj) +{ + obj->ce_refcnt++; + NL_DBG(4, "New reference to object %p, total %d\n", + obj, obj->ce_refcnt); +} + +/** + * Release a reference from an object + * @arg obj object to release reference from + */ +void nl_object_put(struct nl_object *obj) +{ + if (!obj) + return; + + obj->ce_refcnt--; + NL_DBG(4, "Returned object reference %p, %d remaining\n", + obj, obj->ce_refcnt); + + if (obj->ce_refcnt < 0) + BUG(); + + if (obj->ce_refcnt <= 0) + nl_object_free(obj); +} + +/** + * Check whether this object is used by multiple users + * @arg obj object to check + * @return true or false + */ +int nl_object_shared(struct nl_object *obj) +{ + return obj->ce_refcnt > 1; +} + +/** @} */ + +/** + * @name Marks + * @{ + */ + +/** + * Add mark to object + * @arg obj Object to mark + */ +void nl_object_mark(struct nl_object *obj) +{ + obj->ce_flags |= NL_OBJ_MARK; +} + +/** + * Remove mark from object + * @arg obj Object to unmark + */ +void nl_object_unmark(struct nl_object *obj) +{ + obj->ce_flags &= ~NL_OBJ_MARK; +} + +/** + * Return true if object is marked + * @arg obj Object to check + * @return true if object is marked, otherwise false + */ +int nl_object_is_marked(struct nl_object *obj) +{ + return (obj->ce_flags & NL_OBJ_MARK); +} + +/** @} */ + +/** + * @name Utillities + * @{ + */ + +/** + * Dump this object according to the specified parameters + * @arg obj object to dump + * @arg params dumping parameters + */ +void nl_object_dump(struct nl_object *obj, struct nl_dump_params *params) +{ + dump_from_ops(obj, params); +} + +void nl_object_dump_buf(struct nl_object *obj, char *buf, size_t len) +{ + struct nl_dump_params dp = { + .dp_buf = buf, + .dp_buflen = len, + }; + + return nl_object_dump(obj, &dp); +} + +/** + * Check if the identifiers of two objects are identical + * @arg a an object + * @arg b another object of same type + * + * @return true if both objects have equal identifiers, otherwise false. + */ +int nl_object_identical(struct nl_object *a, struct nl_object *b) +{ + struct nl_object_ops *ops = obj_ops(a); + int req_attrs; + + /* Both objects must be of same type */ + if (ops != obj_ops(b)) + return 0; + + req_attrs = ops->oo_id_attrs; + if (req_attrs == ~0) + req_attrs = a->ce_mask & b->ce_mask; + + /* Both objects must provide all required attributes to uniquely + * identify an object */ + if ((a->ce_mask & req_attrs) != req_attrs || + (b->ce_mask & req_attrs) != req_attrs) + return 0; + + /* Can't judge unless we can compare */ + if (ops->oo_compare == NULL) + return 0; + + return !(ops->oo_compare(a, b, req_attrs, 0)); +} + +/** + * Compute bitmask representing difference in attribute values + * @arg a an object + * @arg b another object of same type + * + * The bitmask returned is specific to an object type, each bit set represents + * an attribute which mismatches in either of the two objects. Unavailability + * of an attribute in one object and presence in the other is regarded a + * mismatch as well. + * + * @return Bitmask describing differences or 0 if they are completely identical. + */ +uint32_t nl_object_diff(struct nl_object *a, struct nl_object *b) +{ + struct nl_object_ops *ops = obj_ops(a); + + if (ops != obj_ops(b) || ops->oo_compare == NULL) + return UINT_MAX; + + return ops->oo_compare(a, b, ~0, 0); +} + +/** + * Match a filter against an object + * @arg obj object to check + * @arg filter object of same type acting as filter + * + * @return 1 if the object matches the filter or 0 + * if no filter procedure is available or if the + * filter does not match. + */ +int nl_object_match_filter(struct nl_object *obj, struct nl_object *filter) +{ + struct nl_object_ops *ops = obj_ops(obj); + + if (ops != obj_ops(filter) || ops->oo_compare == NULL) + return 0; + + return !(ops->oo_compare(obj, filter, filter->ce_mask, + LOOSE_COMPARISON)); +} + +/** + * Convert bitmask of attributes to a character string + * @arg obj object of same type as attribute bitmask + * @arg attrs bitmask of attribute types + * @arg buf destination buffer + * @arg len length of destination buffer + * + * Converts the bitmask of attribute types into a list of attribute + * names separated by comas. + * + * @return destination buffer. + */ +char *nl_object_attrs2str(struct nl_object *obj, uint32_t attrs, + char *buf, size_t len) +{ + struct nl_object_ops *ops = obj_ops(obj); + + if (ops->oo_attrs2str != NULL) + return ops->oo_attrs2str(attrs, buf, len); + else { + memset(buf, 0, len); + return buf; + } +} + +/** + * Return list of attributes present in an object + * @arg obj an object + * @arg buf destination buffer + * @arg len length of destination buffer + * + * @return destination buffer. + */ +char *nl_object_attr_list(struct nl_object *obj, char *buf, size_t len) +{ + return nl_object_attrs2str(obj, obj->ce_mask, buf, len); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +int nl_object_get_refcnt(struct nl_object *obj) +{ + return obj->ce_refcnt; +} + +struct nl_cache *nl_object_get_cache(struct nl_object *obj) +{ + return obj->ce_cache; +} + +/** @} */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/.dirstamp b/libnetwork/libnl3/lib/route/.dirstamp new file mode 100644 index 0000000..e69de29 diff --git a/libnetwork/libnl3/lib/route/addr.c b/libnetwork/libnl3/lib/route/addr.c new file mode 100644 index 0000000..deb88ba --- /dev/null +++ b/libnetwork/libnl3/lib/route/addr.c @@ -0,0 +1,1054 @@ +/* + * lib/route/addr.c Addresses + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + * Copyright (c) 2003-2006 Baruch Even , + * Mediatrix Telecom, inc. + */ + +/** + * @ingroup rtnl + * @defgroup rtaddr Addresses + * @brief + * + * @note The maximum size of an address label is IFNAMSIZ. + * + * @note The address may not contain a prefix length if the peer address + * has been specified already. + * + * @par 1) Address Addition + * @code + * // Allocate an empty address object to be filled out with the attributes + * // of the new address. + * struct rtnl_addr *addr = rtnl_addr_alloc(); + * + * // Fill out the mandatory attributes of the new address. Setting the + * // local address will automatically set the address family and the + * // prefix length to the correct values. + * rtnl_addr_set_ifindex(addr, ifindex); + * rtnl_addr_set_local(addr, local_addr); + * + * // The label of the address can be specified, currently only supported + * // by IPv4 and DECnet. + * rtnl_addr_set_label(addr, "mylabel"); + * + * // The peer address can be specified if necessary, in either case a peer + * // address will be sent to the kernel in order to fullfil the interface + * // requirements. If none is set, it will equal the local address. + * // Note: Real peer addresses are only supported by IPv4 for now. + * rtnl_addr_set_peer(addr, peer_addr); + * + * // In case you want to have the address have a scope other than global + * // it may be overwritten using rtnl_addr_set_scope(). The scope currently + * // cannot be set for IPv6 addresses. + * rtnl_addr_set_scope(addr, rtnl_str2scope("site")); + * + * // Broadcast address may be specified using the relevant + * // functions, the address family will be verified if one of the other + * // addresses has been set already. Currently only works for IPv4. + * rtnl_addr_set_broadcast(addr, broadcast_addr); + * + * // Build the netlink message and send it to the kernel, the operation will + * // block until the operation has been completed. Alternatively the required + * // netlink message can be built using rtnl_addr_build_add_request() to be + * // sent out using nl_send_auto_complete(). + * rtnl_addr_add(sk, addr, 0); + * + * // Free the memory + * rtnl_addr_put(addr); + * @endcode + * + * @par 2) Address Deletion + * @code + * // Allocate an empty address object to be filled out with the attributes + * // matching the address to be deleted. Alternatively a fully equipped + * // address object out of a cache can be used instead. + * struct rtnl_addr *addr = rtnl_addr_alloc(); + * + * // The only mandatory parameter besides the address family is the interface + * // index the address is on, i.e. leaving out all other parameters will + * // result in all addresses of the specified address family interface tuple + * // to be deleted. + * rtnl_addr_set_ifindex(addr, ifindex); + * + * // Specyfing the address family manually is only required if neither the + * // local nor peer address have been specified. + * rtnl_addr_set_family(addr, AF_INET); + * + * // Specyfing the local address is optional but the best choice to delete + * // specific addresses. + * rtnl_addr_set_local(addr, local_addr); + * + * // The label of the address can be specified, currently only supported + * // by IPv4 and DECnet. + * rtnl_addr_set_label(addr, "mylabel"); + * + * // The peer address can be specified if necessary, in either case a peer + * // address will be sent to the kernel in order to fullfil the interface + * // requirements. If none is set, it will equal the local address. + * // Note: Real peer addresses are only supported by IPv4 for now. + * rtnl_addr_set_peer(addr, peer_addr); + * + * // Build the netlink message and send it to the kernel, the operation will + * // block until the operation has been completed. Alternatively the required + * // netlink message can be built using rtnl_addr_build_delete_request() + * // to be sent out using nl_send_auto_complete(). + * rtnl_addr_delete(sk, addr, 0); + * + * // Free the memory + * rtnl_addr_put(addr); + * @endcode + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define ADDR_ATTR_FAMILY 0x0001 +#define ADDR_ATTR_PREFIXLEN 0x0002 +#define ADDR_ATTR_FLAGS 0x0004 +#define ADDR_ATTR_SCOPE 0x0008 +#define ADDR_ATTR_IFINDEX 0x0010 +#define ADDR_ATTR_LABEL 0x0020 +#define ADDR_ATTR_CACHEINFO 0x0040 +#define ADDR_ATTR_PEER 0x0080 +#define ADDR_ATTR_LOCAL 0x0100 +#define ADDR_ATTR_BROADCAST 0x0200 +#define ADDR_ATTR_MULTICAST 0x0400 +#define ADDR_ATTR_ANYCAST 0x0800 + +static struct nl_cache_ops rtnl_addr_ops; +static struct nl_object_ops addr_obj_ops; +/** @endcond */ + +static void addr_constructor(struct nl_object *obj) +{ + struct rtnl_addr *addr = nl_object_priv(obj); + + addr->a_scope = RT_SCOPE_NOWHERE; +} + +static void addr_free_data(struct nl_object *obj) +{ + struct rtnl_addr *addr = nl_object_priv(obj); + + if (!addr) + return; + + nl_addr_put(addr->a_peer); + nl_addr_put(addr->a_local); + nl_addr_put(addr->a_bcast); + nl_addr_put(addr->a_multicast); + nl_addr_put(addr->a_anycast); + rtnl_link_put(addr->a_link); +} + +static int addr_clone(struct nl_object *_dst, struct nl_object *_src) +{ + struct rtnl_addr *dst = nl_object_priv(_dst); + struct rtnl_addr *src = nl_object_priv(_src); + + if (src->a_link) { + nl_object_get(OBJ_CAST(src->a_link)); + dst->a_link = src->a_link; + } + + if (src->a_peer) + if (!(dst->a_peer = nl_addr_clone(src->a_peer))) + return -NLE_NOMEM; + + if (src->a_local) + if (!(dst->a_local = nl_addr_clone(src->a_local))) + return -NLE_NOMEM; + + if (src->a_bcast) + if (!(dst->a_bcast = nl_addr_clone(src->a_bcast))) + return -NLE_NOMEM; + + if (src->a_multicast) + if (!(dst->a_multicast = nl_addr_clone(src->a_multicast))) + return -NLE_NOMEM; + + if (src->a_anycast) + if (!(dst->a_anycast = nl_addr_clone(src->a_anycast))) + return -NLE_NOMEM; + + return 0; +} + +static struct nla_policy addr_policy[IFA_MAX+1] = { + [IFA_LABEL] = { .type = NLA_STRING, + .maxlen = IFNAMSIZ }, + [IFA_CACHEINFO] = { .minlen = sizeof(struct ifa_cacheinfo) }, +}; + +static int addr_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *nlh, struct nl_parser_param *pp) +{ + struct rtnl_addr *addr; + struct ifaddrmsg *ifa; + struct nlattr *tb[IFA_MAX+1]; + int err, peer_prefix = 0, family; + struct nl_cache *link_cache; + + addr = rtnl_addr_alloc(); + if (!addr) + return -NLE_NOMEM; + + addr->ce_msgtype = nlh->nlmsg_type; + + err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, addr_policy); + if (err < 0) + goto errout; + + ifa = nlmsg_data(nlh); + addr->a_family = family = ifa->ifa_family; + addr->a_prefixlen = ifa->ifa_prefixlen; + addr->a_flags = ifa->ifa_flags; + addr->a_scope = ifa->ifa_scope; + addr->a_ifindex = ifa->ifa_index; + + addr->ce_mask = (ADDR_ATTR_FAMILY | ADDR_ATTR_PREFIXLEN | + ADDR_ATTR_FLAGS | ADDR_ATTR_SCOPE | ADDR_ATTR_IFINDEX); + + if (tb[IFA_LABEL]) { + nla_strlcpy(addr->a_label, tb[IFA_LABEL], IFNAMSIZ); + addr->ce_mask |= ADDR_ATTR_LABEL; + } + + if (tb[IFA_CACHEINFO]) { + struct ifa_cacheinfo *ca; + + ca = nla_data(tb[IFA_CACHEINFO]); + addr->a_cacheinfo.aci_prefered = ca->ifa_prefered; + addr->a_cacheinfo.aci_valid = ca->ifa_valid; + addr->a_cacheinfo.aci_cstamp = ca->cstamp; + addr->a_cacheinfo.aci_tstamp = ca->tstamp; + addr->ce_mask |= ADDR_ATTR_CACHEINFO; + } + + if (tb[IFA_LOCAL]) { + addr->a_local = nl_addr_alloc_attr(tb[IFA_LOCAL], family); + if (!addr->a_local) + goto errout_nomem; + addr->ce_mask |= ADDR_ATTR_LOCAL; + } + + if (tb[IFA_ADDRESS]) { + struct nl_addr *a; + + a = nl_addr_alloc_attr(tb[IFA_ADDRESS], family); + if (!a) + goto errout_nomem; + + /* IPv6 sends the local address as IFA_ADDRESS with + * no IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS + * with IFA_ADDRESS being the peer address if they differ */ + if (!tb[IFA_LOCAL] || !nl_addr_cmp(a, addr->a_local)) { + nl_addr_put(addr->a_local); + addr->a_local = a; + addr->ce_mask |= ADDR_ATTR_LOCAL; + } else { + addr->a_peer = a; + addr->ce_mask |= ADDR_ATTR_PEER; + peer_prefix = 1; + } + } + + nl_addr_set_prefixlen(peer_prefix ? addr->a_peer : addr->a_local, + addr->a_prefixlen); + + if (tb[IFA_BROADCAST]) { + addr->a_bcast = nl_addr_alloc_attr(tb[IFA_BROADCAST], family); + if (!addr->a_bcast) + goto errout_nomem; + + addr->ce_mask |= ADDR_ATTR_BROADCAST; + } + + if (tb[IFA_MULTICAST]) { + addr->a_multicast = nl_addr_alloc_attr(tb[IFA_MULTICAST], + family); + if (!addr->a_multicast) + goto errout_nomem; + + addr->ce_mask |= ADDR_ATTR_MULTICAST; + } + + if (tb[IFA_ANYCAST]) { + addr->a_anycast = nl_addr_alloc_attr(tb[IFA_ANYCAST], + family); + if (!addr->a_anycast) + goto errout_nomem; + + addr->ce_mask |= ADDR_ATTR_ANYCAST; + } + + if ((link_cache = __nl_cache_mngt_require("route/link"))) { + struct rtnl_link *link; + + if ((link = rtnl_link_get(link_cache, addr->a_ifindex))) { + rtnl_addr_set_link(addr, link); + + /* rtnl_addr_set_link incs refcnt */ + rtnl_link_put(link); + } + } + + err = pp->pp_cb((struct nl_object *) addr, pp); +errout: + rtnl_addr_put(addr); + + return err; + +errout_nomem: + err = -NLE_NOMEM; + goto errout; +} + +static int addr_request_update(struct nl_cache *cache, struct nl_sock *sk) +{ + return nl_rtgen_request(sk, RTM_GETADDR, AF_UNSPEC, NLM_F_DUMP); +} + +static void addr_dump_line(struct nl_object *obj, struct nl_dump_params *p) +{ + struct rtnl_addr *addr = (struct rtnl_addr *) obj; + struct nl_cache *link_cache; + char buf[128]; + + link_cache = nl_cache_mngt_require("route/link"); + + if (addr->ce_mask & ADDR_ATTR_LOCAL) + nl_dump_line(p, "%s", + nl_addr2str(addr->a_local, buf, sizeof(buf))); + else + nl_dump_line(p, "none"); + + if (addr->ce_mask & ADDR_ATTR_PEER) + nl_dump(p, " peer %s", + nl_addr2str(addr->a_peer, buf, sizeof(buf))); + + nl_dump(p, " %s ", nl_af2str(addr->a_family, buf, sizeof(buf))); + + if (link_cache) + nl_dump(p, "dev %s ", + rtnl_link_i2name(link_cache, addr->a_ifindex, + buf, sizeof(buf))); + else + nl_dump(p, "dev %d ", addr->a_ifindex); + + nl_dump(p, "scope %s", + rtnl_scope2str(addr->a_scope, buf, sizeof(buf))); + + rtnl_addr_flags2str(addr->a_flags, buf, sizeof(buf)); + if (buf[0]) + nl_dump(p, " <%s>", buf); + + nl_dump(p, "\n"); +} + +static void addr_dump_details(struct nl_object *obj, struct nl_dump_params *p) +{ + struct rtnl_addr *addr = (struct rtnl_addr *) obj; + char buf[128]; + + addr_dump_line(obj, p); + + if (addr->ce_mask & (ADDR_ATTR_LABEL | ADDR_ATTR_BROADCAST | + ADDR_ATTR_MULTICAST)) { + nl_dump_line(p, " "); + + if (addr->ce_mask & ADDR_ATTR_LABEL) + nl_dump(p, " label %s", addr->a_label); + + if (addr->ce_mask & ADDR_ATTR_BROADCAST) + nl_dump(p, " broadcast %s", + nl_addr2str(addr->a_bcast, buf, sizeof(buf))); + + if (addr->ce_mask & ADDR_ATTR_MULTICAST) + nl_dump(p, " multicast %s", + nl_addr2str(addr->a_multicast, buf, + sizeof(buf))); + + if (addr->ce_mask & ADDR_ATTR_ANYCAST) + nl_dump(p, " anycast %s", + nl_addr2str(addr->a_anycast, buf, + sizeof(buf))); + + nl_dump(p, "\n"); + } + + if (addr->ce_mask & ADDR_ATTR_CACHEINFO) { + struct rtnl_addr_cacheinfo *ci = &addr->a_cacheinfo; + + nl_dump_line(p, " valid-lifetime %s", + ci->aci_valid == 0xFFFFFFFFU ? "forever" : + nl_msec2str(ci->aci_valid * 1000, + buf, sizeof(buf))); + + nl_dump(p, " preferred-lifetime %s\n", + ci->aci_prefered == 0xFFFFFFFFU ? "forever" : + nl_msec2str(ci->aci_prefered * 1000, + buf, sizeof(buf))); + + nl_dump_line(p, " created boot-time+%s ", + nl_msec2str(addr->a_cacheinfo.aci_cstamp * 10, + buf, sizeof(buf))); + + nl_dump(p, "last-updated boot-time+%s\n", + nl_msec2str(addr->a_cacheinfo.aci_tstamp * 10, + buf, sizeof(buf))); + } +} + +static void addr_dump_stats(struct nl_object *obj, struct nl_dump_params *p) +{ + addr_dump_details(obj, p); +} + +static int addr_compare(struct nl_object *_a, struct nl_object *_b, + uint32_t attrs, int flags) +{ + struct rtnl_addr *a = (struct rtnl_addr *) _a; + struct rtnl_addr *b = (struct rtnl_addr *) _b; + int diff = 0; + +#define ADDR_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ADDR_ATTR_##ATTR, a, b, EXPR) + + diff |= ADDR_DIFF(IFINDEX, a->a_ifindex != b->a_ifindex); + diff |= ADDR_DIFF(FAMILY, a->a_family != b->a_family); + diff |= ADDR_DIFF(SCOPE, a->a_scope != b->a_scope); + diff |= ADDR_DIFF(LABEL, strcmp(a->a_label, b->a_label)); + diff |= ADDR_DIFF(PEER, nl_addr_cmp(a->a_peer, b->a_peer)); + diff |= ADDR_DIFF(LOCAL, nl_addr_cmp(a->a_local, b->a_local)); + diff |= ADDR_DIFF(MULTICAST, nl_addr_cmp(a->a_multicast, + b->a_multicast)); + diff |= ADDR_DIFF(BROADCAST, nl_addr_cmp(a->a_bcast, b->a_bcast)); + diff |= ADDR_DIFF(ANYCAST, nl_addr_cmp(a->a_anycast, b->a_anycast)); + + if (flags & LOOSE_COMPARISON) + diff |= ADDR_DIFF(FLAGS, + (a->a_flags ^ b->a_flags) & b->a_flag_mask); + else + diff |= ADDR_DIFF(FLAGS, a->a_flags != b->a_flags); + +#undef ADDR_DIFF + + return diff; +} + +static const struct trans_tbl addr_attrs[] = { + __ADD(ADDR_ATTR_FAMILY, family) + __ADD(ADDR_ATTR_PREFIXLEN, prefixlen) + __ADD(ADDR_ATTR_FLAGS, flags) + __ADD(ADDR_ATTR_SCOPE, scope) + __ADD(ADDR_ATTR_IFINDEX, ifindex) + __ADD(ADDR_ATTR_LABEL, label) + __ADD(ADDR_ATTR_CACHEINFO, cacheinfo) + __ADD(ADDR_ATTR_PEER, peer) + __ADD(ADDR_ATTR_LOCAL, local) + __ADD(ADDR_ATTR_BROADCAST, broadcast) + __ADD(ADDR_ATTR_MULTICAST, multicast) +}; + +static char *addr_attrs2str(int attrs, char *buf, size_t len) +{ + return __flags2str(attrs, buf, len, addr_attrs, + ARRAY_SIZE(addr_attrs)); +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct rtnl_addr *rtnl_addr_alloc(void) +{ + return (struct rtnl_addr *) nl_object_alloc(&addr_obj_ops); +} + +void rtnl_addr_put(struct rtnl_addr *addr) +{ + nl_object_put((struct nl_object *) addr); +} + +/** @} */ + +/** + * @name Cache Management + * @{ + */ + +int rtnl_addr_alloc_cache(struct nl_sock *sk, struct nl_cache **result) +{ + return nl_cache_alloc_and_fill(&rtnl_addr_ops, sk, result); +} + +/** + * Search address in cache + * @arg cache Address cache + * @arg ifindex Interface index of address + * @arg addr Local address part + * + * Searches address cache previously allocated with rtnl_addr_alloc_cache() + * for an address with a matching local address. + * + * The reference counter is incremented before returning the address, therefore + * the reference must be given back with rtnl_addr_put() after usage. + * + * @return Address object or NULL if no match was found. + */ +struct rtnl_addr *rtnl_addr_get(struct nl_cache *cache, int ifindex, + struct nl_addr *addr) +{ + struct rtnl_addr *a; + + if (cache->c_ops != &rtnl_addr_ops) + return NULL; + + nl_list_for_each_entry(a, &cache->c_items, ce_list) { + if (ifindex && a->a_ifindex != ifindex) + continue; + + if (a->ce_mask & ADDR_ATTR_LOCAL && + !nl_addr_cmp(a->a_local, addr)) { + nl_object_get((struct nl_object *) a); + return a; + } + } + + return NULL; +} + +/** @} */ + +static int build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags, + struct nl_msg **result) +{ + struct nl_msg *msg; + struct ifaddrmsg am = { + .ifa_family = tmpl->a_family, + .ifa_index = tmpl->a_ifindex, + .ifa_prefixlen = tmpl->a_prefixlen, + }; + + if (tmpl->ce_mask & ADDR_ATTR_SCOPE) + am.ifa_scope = tmpl->a_scope; + else { + /* compatibility hack */ + if (tmpl->a_family == AF_INET && + tmpl->ce_mask & ADDR_ATTR_LOCAL && + *((char *) nl_addr_get_binary_addr(tmpl->a_local)) == 127) + am.ifa_scope = RT_SCOPE_HOST; + else + am.ifa_scope = RT_SCOPE_UNIVERSE; + } + + msg = nlmsg_alloc_simple(cmd, flags); + if (!msg) + return -NLE_NOMEM; + + if (nlmsg_append(msg, &am, sizeof(am), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + if (tmpl->ce_mask & ADDR_ATTR_LOCAL) + NLA_PUT_ADDR(msg, IFA_LOCAL, tmpl->a_local); + + if (tmpl->ce_mask & ADDR_ATTR_PEER) + NLA_PUT_ADDR(msg, IFA_ADDRESS, tmpl->a_peer); + else if (tmpl->ce_mask & ADDR_ATTR_LOCAL) + NLA_PUT_ADDR(msg, IFA_ADDRESS, tmpl->a_local); + + if (tmpl->ce_mask & ADDR_ATTR_LABEL) + NLA_PUT_STRING(msg, IFA_LABEL, tmpl->a_label); + + if (tmpl->ce_mask & ADDR_ATTR_BROADCAST) + NLA_PUT_ADDR(msg, IFA_BROADCAST, tmpl->a_bcast); + + if (tmpl->ce_mask & ADDR_ATTR_CACHEINFO) { + struct ifa_cacheinfo ca = { + .ifa_valid = tmpl->a_cacheinfo.aci_valid, + .ifa_prefered = tmpl->a_cacheinfo.aci_prefered, + }; + + NLA_PUT(msg, IFA_CACHEINFO, sizeof(ca), &ca); + } + + + *result = msg; + return 0; + +nla_put_failure: + nlmsg_free(msg); + return -NLE_MSGSIZE; +} + +/** + * @name Addition + * @{ + */ + +/** + * Build netlink request message to request addition of new address + * @arg addr Address object representing the new address. + * @arg flags Additional netlink message flags. + * @arg result Pointer to store resulting message. + * + * Builds a new netlink message requesting the addition of a new + * address. The netlink message header isn't fully equipped with + * all relevant fields and must thus be sent out via nl_send_auto_complete() + * or supplemented as needed. + * + * Minimal required attributes: + * - interface index (rtnl_addr_set_ifindex()) + * - local address (rtnl_addr_set_local()) + * + * The scope will default to universe except for loopback addresses in + * which case a host scope is used if not specified otherwise. + * + * @note Free the memory after usage using nlmsg_free(). + * + * @return 0 on success or a negative error code. + */ +int rtnl_addr_build_add_request(struct rtnl_addr *addr, int flags, + struct nl_msg **result) +{ + int required = ADDR_ATTR_IFINDEX | ADDR_ATTR_FAMILY | + ADDR_ATTR_PREFIXLEN | ADDR_ATTR_LOCAL; + + if ((addr->ce_mask & required) != required) + return -NLE_MISSING_ATTR; + + return build_addr_msg(addr, RTM_NEWADDR, NLM_F_CREATE | flags, result); +} + +/** + * Request addition of new address + * @arg sk Netlink socket. + * @arg addr Address object representing the new address. + * @arg flags Additional netlink message flags. + * + * Builds a netlink message by calling rtnl_addr_build_add_request(), + * sends the request to the kernel and waits for the next ACK to be + * received and thus blocks until the request has been fullfilled. + * + * @see rtnl_addr_build_add_request() + * + * @return 0 on sucess or a negative error if an error occured. + */ +int rtnl_addr_add(struct nl_sock *sk, struct rtnl_addr *addr, int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_addr_build_add_request(addr, flags, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +/** @} */ + +/** + * @name Deletion + * @{ + */ + +/** + * Build a netlink request message to request deletion of an address + * @arg addr Address object to be deleteted. + * @arg flags Additional netlink message flags. + * @arg result Pointer to store resulting message. + * + * Builds a new netlink message requesting a deletion of an address. + * The netlink message header isn't fully equipped with all relevant + * fields and must thus be sent out via nl_send_auto_complete() + * or supplemented as needed. + * + * Minimal required attributes: + * - interface index (rtnl_addr_set_ifindex()) + * - address family (rtnl_addr_set_family()) + * + * Optional attributes: + * - local address (rtnl_addr_set_local()) + * - label (rtnl_addr_set_label(), IPv4/DECnet only) + * - peer address (rtnl_addr_set_peer(), IPv4 only) + * + * @note Free the memory after usage using nlmsg_free(). + * + * @return 0 on success or a negative error code. + */ +int rtnl_addr_build_delete_request(struct rtnl_addr *addr, int flags, + struct nl_msg **result) +{ + int required = ADDR_ATTR_IFINDEX | ADDR_ATTR_FAMILY; + + if ((addr->ce_mask & required) != required) + return -NLE_MISSING_ATTR; + + return build_addr_msg(addr, RTM_DELADDR, flags, result); +} + +/** + * Request deletion of an address + * @arg sk Netlink socket. + * @arg addr Address object to be deleted. + * @arg flags Additional netlink message flags. + * + * Builds a netlink message by calling rtnl_addr_build_delete_request(), + * sends the request to the kernel and waits for the next ACK to be + * received and thus blocks until the request has been fullfilled. + * + * @see rtnl_addr_build_delete_request(); + * + * @return 0 on sucess or a negative error if an error occured. + */ +int rtnl_addr_delete(struct nl_sock *sk, struct rtnl_addr *addr, int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_addr_build_delete_request(addr, flags, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +int rtnl_addr_set_label(struct rtnl_addr *addr, const char *label) +{ + if (strlen(label) > sizeof(addr->a_label) - 1) + return -NLE_RANGE; + + strcpy(addr->a_label, label); + addr->ce_mask |= ADDR_ATTR_LABEL; + + return 0; +} + +char *rtnl_addr_get_label(struct rtnl_addr *addr) +{ + if (addr->ce_mask & ADDR_ATTR_LABEL) + return addr->a_label; + else + return NULL; +} + +void rtnl_addr_set_ifindex(struct rtnl_addr *addr, int ifindex) +{ + addr->a_ifindex = ifindex; + addr->ce_mask |= ADDR_ATTR_IFINDEX; +} + +int rtnl_addr_get_ifindex(struct rtnl_addr *addr) +{ + return addr->a_ifindex; +} + +void rtnl_addr_set_link(struct rtnl_addr *addr, struct rtnl_link *link) +{ + rtnl_link_put(addr->a_link); + + if (!link) + return; + + nl_object_get(OBJ_CAST(link)); + addr->a_link = link; + addr->a_ifindex = link->l_index; + addr->ce_mask |= ADDR_ATTR_IFINDEX; +} + +struct rtnl_link *rtnl_addr_get_link(struct rtnl_addr *addr) +{ + if (addr->a_link) { + nl_object_get(OBJ_CAST(addr->a_link)); + return addr->a_link; + } + + return NULL; +} + +void rtnl_addr_set_family(struct rtnl_addr *addr, int family) +{ + addr->a_family = family; + addr->ce_mask |= ADDR_ATTR_FAMILY; +} + +int rtnl_addr_get_family(struct rtnl_addr *addr) +{ + return addr->a_family; +} + +void rtnl_addr_set_prefixlen(struct rtnl_addr *addr, int prefix) +{ + addr->a_prefixlen = prefix; + addr->ce_mask |= ADDR_ATTR_PREFIXLEN; +} + +int rtnl_addr_get_prefixlen(struct rtnl_addr *addr) +{ + return addr->a_prefixlen; +} + +void rtnl_addr_set_scope(struct rtnl_addr *addr, int scope) +{ + addr->a_scope = scope; + addr->ce_mask |= ADDR_ATTR_SCOPE; +} + +int rtnl_addr_get_scope(struct rtnl_addr *addr) +{ + return addr->a_scope; +} + +void rtnl_addr_set_flags(struct rtnl_addr *addr, unsigned int flags) +{ + addr->a_flag_mask |= flags; + addr->a_flags |= flags; + addr->ce_mask |= ADDR_ATTR_FLAGS; +} + +void rtnl_addr_unset_flags(struct rtnl_addr *addr, unsigned int flags) +{ + addr->a_flag_mask |= flags; + addr->a_flags &= ~flags; + addr->ce_mask |= ADDR_ATTR_FLAGS; +} + +unsigned int rtnl_addr_get_flags(struct rtnl_addr *addr) +{ + return addr->a_flags; +} + +static inline int __assign_addr(struct rtnl_addr *addr, struct nl_addr **pos, + struct nl_addr *new, int flag) +{ + if (addr->ce_mask & ADDR_ATTR_FAMILY) { + if (new->a_family != addr->a_family) + return -NLE_AF_MISMATCH; + } else + addr->a_family = new->a_family; + + if (*pos) + nl_addr_put(*pos); + + *pos = nl_addr_get(new); + addr->ce_mask |= (flag | ADDR_ATTR_FAMILY); + + return 0; +} + +int rtnl_addr_set_local(struct rtnl_addr *addr, struct nl_addr *local) +{ + int err; + + err = __assign_addr(addr, &addr->a_local, local, ADDR_ATTR_LOCAL); + if (err < 0) + return err; + + if (!(addr->ce_mask & ADDR_ATTR_PEER)) { + addr->a_prefixlen = nl_addr_get_prefixlen(addr->a_local); + addr->ce_mask |= ADDR_ATTR_PREFIXLEN; + } + + return 0; +} + +struct nl_addr *rtnl_addr_get_local(struct rtnl_addr *addr) +{ + return addr->a_local; +} + +int rtnl_addr_set_peer(struct rtnl_addr *addr, struct nl_addr *peer) +{ + return __assign_addr(addr, &addr->a_peer, peer, ADDR_ATTR_PEER); + + addr->a_prefixlen = nl_addr_get_prefixlen(addr->a_peer); + addr->ce_mask |= ADDR_ATTR_PREFIXLEN; + + return 0; +} + +struct nl_addr *rtnl_addr_get_peer(struct rtnl_addr *addr) +{ + return addr->a_peer; +} + +int rtnl_addr_set_broadcast(struct rtnl_addr *addr, struct nl_addr *bcast) +{ + return __assign_addr(addr, &addr->a_bcast, bcast, ADDR_ATTR_BROADCAST); +} + +struct nl_addr *rtnl_addr_get_broadcast(struct rtnl_addr *addr) +{ + return addr->a_bcast; +} + +int rtnl_addr_set_multicast(struct rtnl_addr *addr, struct nl_addr *multicast) +{ + return __assign_addr(addr, &addr->a_multicast, multicast, + ADDR_ATTR_MULTICAST); +} + +struct nl_addr *rtnl_addr_get_multicast(struct rtnl_addr *addr) +{ + return addr->a_multicast; +} + +int rtnl_addr_set_anycast(struct rtnl_addr *addr, struct nl_addr *anycast) +{ + return __assign_addr(addr, &addr->a_anycast, anycast, + ADDR_ATTR_ANYCAST); +} + +struct nl_addr *rtnl_addr_get_anycast(struct rtnl_addr *addr) +{ + return addr->a_anycast; +} + +uint32_t rtnl_addr_get_valid_lifetime(struct rtnl_addr *addr) +{ + if (addr->ce_mask & ADDR_ATTR_CACHEINFO) + return addr->a_cacheinfo.aci_valid; + else + return 0xFFFFFFFFU; +} + +void rtnl_addr_set_valid_lifetime(struct rtnl_addr *addr, uint32_t lifetime) +{ + addr->a_cacheinfo.aci_valid = lifetime; + addr->ce_mask |= ADDR_ATTR_CACHEINFO; +} + +uint32_t rtnl_addr_get_preferred_lifetime(struct rtnl_addr *addr) +{ + if (addr->ce_mask & ADDR_ATTR_CACHEINFO) + return addr->a_cacheinfo.aci_prefered; + else + return 0xFFFFFFFFU; +} + +void rtnl_addr_set_preferred_lifetime(struct rtnl_addr *addr, uint32_t lifetime) +{ + addr->a_cacheinfo.aci_prefered = lifetime; + addr->ce_mask |= ADDR_ATTR_CACHEINFO; +} + +uint32_t rtnl_addr_get_create_time(struct rtnl_addr *addr) +{ + return addr->a_cacheinfo.aci_cstamp; +} + +uint32_t rtnl_addr_get_last_update_time(struct rtnl_addr *addr) +{ + return addr->a_cacheinfo.aci_tstamp; +} + +/** @} */ + +/** + * @name Flags Translations + * @{ + */ + +static const struct trans_tbl addr_flags[] = { + __ADD(IFA_F_SECONDARY, secondary) + __ADD(IFA_F_NODAD, nodad) + __ADD(IFA_F_OPTIMISTIC, optimistic) + __ADD(IFA_F_HOMEADDRESS, homeaddress) + __ADD(IFA_F_DEPRECATED, deprecated) + __ADD(IFA_F_TENTATIVE, tentative) + __ADD(IFA_F_PERMANENT, permanent) +}; + +char *rtnl_addr_flags2str(int flags, char *buf, size_t size) +{ + return __flags2str(flags, buf, size, addr_flags, + ARRAY_SIZE(addr_flags)); +} + +int rtnl_addr_str2flags(const char *name) +{ + return __str2flags(name, addr_flags, ARRAY_SIZE(addr_flags)); +} + +/** @} */ + +static struct nl_object_ops addr_obj_ops = { + .oo_name = "route/addr", + .oo_size = sizeof(struct rtnl_addr), + .oo_constructor = addr_constructor, + .oo_free_data = addr_free_data, + .oo_clone = addr_clone, + .oo_dump = { + [NL_DUMP_LINE] = addr_dump_line, + [NL_DUMP_DETAILS] = addr_dump_details, + [NL_DUMP_STATS] = addr_dump_stats, + }, + .oo_compare = addr_compare, + .oo_attrs2str = addr_attrs2str, + .oo_id_attrs = (ADDR_ATTR_FAMILY | ADDR_ATTR_IFINDEX | + ADDR_ATTR_LOCAL | ADDR_ATTR_PREFIXLEN), +}; + +static struct nl_af_group addr_groups[] = { + { AF_INET, RTNLGRP_IPV4_IFADDR }, + { AF_INET6, RTNLGRP_IPV6_IFADDR }, + { END_OF_GROUP_LIST }, +}; + +static struct nl_cache_ops rtnl_addr_ops = { + .co_name = "route/addr", + .co_hdrsize = sizeof(struct ifaddrmsg), + .co_msgtypes = { + { RTM_NEWADDR, NL_ACT_NEW, "new" }, + { RTM_DELADDR, NL_ACT_DEL, "del" }, + { RTM_GETADDR, NL_ACT_GET, "get" }, + END_OF_MSGTYPES_LIST, + }, + .co_protocol = NETLINK_ROUTE, + .co_groups = addr_groups, + .co_request_update = addr_request_update, + .co_msg_parser = addr_msg_parser, + .co_obj_ops = &addr_obj_ops, +}; + +static void __init addr_init(void) +{ + nl_cache_mngt_register(&rtnl_addr_ops); +} + +static void __exit addr_exit(void) +{ + nl_cache_mngt_unregister(&rtnl_addr_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/class.c b/libnetwork/libnl3/lib/route/class.c new file mode 100644 index 0000000..2a9606b --- /dev/null +++ b/libnetwork/libnl3/lib/route/class.c @@ -0,0 +1,473 @@ +/* + * lib/route/class.c Traffic Classes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +/** + * @ingroup tc + * @defgroup class Traffic Classes + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct nl_cache_ops rtnl_class_ops; +static struct nl_object_ops class_obj_ops; + +static void class_dump_details(struct rtnl_tc *tc, struct nl_dump_params *p) +{ + struct rtnl_class *class = (struct rtnl_class *) tc; + char buf[32]; + + if (class->c_info) + nl_dump(p, "child-qdisc %s ", + rtnl_tc_handle2str(class->c_info, buf, sizeof(buf))); +} + + +static int class_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *nlh, struct nl_parser_param *pp) +{ + struct rtnl_class *class; + int err; + + if (!(class = rtnl_class_alloc())) + return -NLE_NOMEM; + + if ((err = rtnl_tc_msg_parse(nlh, TC_CAST(class))) < 0) + goto errout; + + err = pp->pp_cb(OBJ_CAST(class), pp); +errout: + rtnl_class_put(class); + + return err; +} + +static int class_request_update(struct nl_cache *cache, struct nl_sock *sk) +{ + struct tcmsg tchdr = { + .tcm_family = AF_UNSPEC, + .tcm_ifindex = cache->c_iarg1, + }; + + return nl_send_simple(sk, RTM_GETTCLASS, NLM_F_DUMP, &tchdr, + sizeof(tchdr)); +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct rtnl_class *rtnl_class_alloc(void) +{ + struct rtnl_tc *tc; + + tc = TC_CAST(nl_object_alloc(&class_obj_ops)); + if (tc) + tc->tc_type = RTNL_TC_TYPE_CLASS; + + return (struct rtnl_class *) tc; +} + +void rtnl_class_put(struct rtnl_class *class) +{ + nl_object_put((struct nl_object *) class); +} + +/** @} */ + + +/** + * @name Addition/Modification/Deletion + * @{ + */ + +static int class_build(struct rtnl_class *class, int type, int flags, + struct nl_msg **result) +{ + int needed = TCA_ATTR_PARENT | TCA_ATTR_HANDLE; + + if ((class->ce_mask & needed) == needed && + TC_H_MAJ(class->c_parent) && TC_H_MAJ(class->c_handle) && + TC_H_MAJ(class->c_parent) != TC_H_MAJ(class->c_handle)) { + APPBUG("TC_H_MAJ(parent) must match TC_H_MAJ(handle)"); + return -NLE_INVAL; + } + + return rtnl_tc_msg_build(TC_CAST(class), type, flags, result); +} + +/** + * Build a netlink message requesting the addition of a traffic class + * @arg class Traffic class to add + * @arg flags Additional netlink message flags + * @arg result Pointer to store resulting netlink message + * + * The behaviour of this function is identical to rtnl_class_add() with + * the exception that it will not send the message but return it int the + * provided return pointer instead. + * + * @see rtnl_class_add() + * + * @return 0 on success or a negative error code. + */ +int rtnl_class_build_add_request(struct rtnl_class *class, int flags, + struct nl_msg **result) +{ + return class_build(class, RTM_NEWTCLASS, flags, result); +} + +/** + * Add/Update traffic class + * @arg sk Netlink socket + * @arg class Traffic class to add + * @arg flags Additional netlink message flags + * + * Builds a \c RTM_NEWTCLASS netlink message requesting the addition + * of a new traffic class and sends the message to the kernel. The + * configuration of the traffic class is derived from the attributes + * of the specified traffic class. + * + * The following flags may be specified: + * - \c NLM_F_CREATE: Create traffic class if it does not exist, + * otherwise -NLE_OBJ_NOTFOUND is returned. + * - \c NLM_F_EXCL: Return -NLE_EXISTS if a traffic class with + * matching handle exists already. + * + * Existing traffic classes with matching handles will be updated, + * unless the flag \c NLM_F_EXCL is specified. If no matching traffic + * class exists, it will be created if the flag \c NLM_F_CREATE is set, + * otherwise the error -NLE_OBJ_NOTFOUND is returned. + * + * If the parent qdisc does not support classes, the error + * \c NLE_OPNOTSUPP is returned. + * + * After sending, the function will wait for the ACK or an eventual + * error message to be received and will therefore block until the + * operation has been completed. + * + * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause + * this function to return immediately after sending. In this case, + * it is the responsibility of the caller to handle any error + * messages returned. + * + * @return 0 on success or a negative error code. + */ +int rtnl_class_add(struct nl_sock *sk, struct rtnl_class *class, int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_class_build_add_request(class, flags, &msg)) < 0) + return err; + + return nl_send_sync(sk, msg); +} + +/** + * Build netlink message requesting the deletion of a traffic class + * @arg class Traffic class to delete + * @arg result Pointer to store resulting netlink message + * + * The behaviour of this function is identical to rtnl_class_delete() with + * the exception that it will not send the message but return it in the + * provided return pointer instead. + * + * @see rtnl_class_delete() + * + * @return 0 on success or a negative error code. + */ +int rtnl_class_build_delete_request(struct rtnl_class *class, struct nl_msg **result) +{ + struct nl_msg *msg; + struct tcmsg tchdr; + int required = TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE; + + if ((class->ce_mask & required) != required) { + APPBUG("ifindex and handle must be specified"); + return -NLE_MISSING_ATTR; + } + + if (!(msg = nlmsg_alloc_simple(RTM_DELTCLASS, 0))) + return -NLE_NOMEM; + + memset(&tchdr, 0, sizeof(tchdr)); + tchdr.tcm_family = AF_UNSPEC; + tchdr.tcm_ifindex = class->c_ifindex; + tchdr.tcm_handle = class->c_handle; + + if (class->ce_mask & TCA_ATTR_PARENT) + tchdr.tcm_parent = class->c_parent; + + if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) { + nlmsg_free(msg); + return -NLE_MSGSIZE; + } + + *result = msg; + return 0; +} + +/** + * Delete traffic class + * @arg sk Netlink socket + * @arg class Traffic class to delete + * + * Builds a \c RTM_DELTCLASS netlink message requesting the deletion + * of a traffic class and sends the message to the kernel. + * + * The message is constructed out of the following attributes: + * - \c ifindex and \c handle (required) + * - \c parent (optional, must match if provided) + * + * All other class attributes including all class type specific + * attributes are ignored. + * + * After sending, the function will wait for the ACK or an eventual + * error message to be received and will therefore block until the + * operation has been completed. + * + * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause + * this function to return immediately after sending. In this case, + * it is the responsibility of the caller to handle any error + * messages returned. + * + * @return 0 on success or a negative error code. + */ +int rtnl_class_delete(struct nl_sock *sk, struct rtnl_class *class) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_class_build_delete_request(class, &msg)) < 0) + return err; + + return nl_send_sync(sk, msg); +} + +/** @} */ + +/** + * @name Leaf Qdisc + * @{ + */ + +/** + * Lookup the leaf qdisc of a traffic class + * @arg class the parent traffic class + * @arg cache a qdisc cache allocated using rtnl_qdisc_alloc_cache() + * + * @return Matching Qdisc or NULL if the traffic class has no leaf qdisc + */ +struct rtnl_qdisc *rtnl_class_leaf_qdisc(struct rtnl_class *class, + struct nl_cache *cache) +{ + struct rtnl_qdisc *leaf; + + if (!class->c_info) + return NULL; + + leaf = rtnl_qdisc_get_by_parent(cache, class->c_ifindex, + class->c_handle); + if (!leaf || leaf->q_handle != class->c_info) + return NULL; + + return leaf; +} + +/** @} */ + +/** + * @name Cache Related Functions + * @{ + */ + +/** + * Allocate a cache and fill it with all configured traffic classes + * @arg sk Netlink socket + * @arg ifindex Interface index of the network device + * @arg result Pointer to store the created cache + * + * Allocates a new traffic class cache and fills it with a list of all + * configured traffic classes on a specific network device. Release the + * cache with nl_cache_free(). + * + * @return 0 on success or a negative error code. + */ +int rtnl_class_alloc_cache(struct nl_sock *sk, int ifindex, + struct nl_cache **result) +{ + struct nl_cache * cache; + int err; + + if (!ifindex) { + APPBUG("ifindex must be specified"); + return -NLE_INVAL; + } + + if (!(cache = nl_cache_alloc(&rtnl_class_ops))) + return -NLE_NOMEM; + + cache->c_iarg1 = ifindex; + + if (sk && (err = nl_cache_refill(sk, cache)) < 0) { + nl_cache_free(cache); + return err; + } + + *result = cache; + return 0; +} + +/** + * Search traffic class by interface index and handle + * @arg cache Traffic class cache + * @arg ifindex Interface index + * @arg handle ID of traffic class + * + * Searches a traffic class cache previously allocated with + * rtnl_class_alloc_cache() and searches for a traffi class matching + * the interface index and handle. + * + * The reference counter is incremented before returning the traffic + * class, therefore the reference must be given back with rtnl_class_put() + * after usage. + * + * @return Traffic class or NULL if no match was found. + */ +struct rtnl_class *rtnl_class_get(struct nl_cache *cache, int ifindex, + uint32_t handle) +{ + struct rtnl_class *class; + + if (cache->c_ops != &rtnl_class_ops) + return NULL; + + nl_list_for_each_entry(class, &cache->c_items, ce_list) { + if (class->c_handle == handle && class->c_ifindex == ifindex) { + nl_object_get((struct nl_object *) class); + return class; + } + } + return NULL; +} + +/** @} */ + +/** + * @name Deprecated Functions + * @{ + */ + +/** + * Call a callback for each child of a class + * + * @deprecated Use of this function is deprecated, it does not allow + * to handle the out of memory situation that can occur. + */ +void rtnl_class_foreach_child(struct rtnl_class *class, struct nl_cache *cache, + void (*cb)(struct nl_object *, void *), void *arg) +{ + struct rtnl_class *filter; + + filter = rtnl_class_alloc(); + if (!filter) + return; + + rtnl_tc_set_parent(TC_CAST(filter), class->c_handle); + rtnl_tc_set_ifindex(TC_CAST(filter), class->c_ifindex); + rtnl_tc_set_kind(TC_CAST(filter), class->c_kind); + + nl_cache_foreach_filter(cache, OBJ_CAST(filter), cb, arg); + rtnl_class_put(filter); +} + +/** + * Call a callback for each classifier attached to the class + * + * @deprecated Use of this function is deprecated, it does not allow + * to handle the out of memory situation that can occur. + */ +void rtnl_class_foreach_cls(struct rtnl_class *class, struct nl_cache *cache, + void (*cb)(struct nl_object *, void *), void *arg) +{ + struct rtnl_cls *filter; + + filter = rtnl_cls_alloc(); + if (!filter) + return; + + rtnl_tc_set_ifindex((struct rtnl_tc *) filter, class->c_ifindex); + rtnl_tc_set_parent((struct rtnl_tc *) filter, class->c_parent); + + nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg); + rtnl_cls_put(filter); +} + +/** @} */ + +static struct rtnl_tc_type_ops class_ops = { + .tt_type = RTNL_TC_TYPE_CLASS, + .tt_dump_prefix = "class", + .tt_dump = { + [NL_DUMP_DETAILS] = class_dump_details, + }, +}; + +static struct nl_object_ops class_obj_ops = { + .oo_name = "route/class", + .oo_size = sizeof(struct rtnl_class), + .oo_free_data = rtnl_tc_free_data, + .oo_clone = rtnl_tc_clone, + .oo_dump = { + [NL_DUMP_LINE] = rtnl_tc_dump_line, + [NL_DUMP_DETAILS] = rtnl_tc_dump_details, + [NL_DUMP_STATS] = rtnl_tc_dump_stats, + }, + .oo_compare = rtnl_tc_compare, + .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE), +}; + +static struct nl_cache_ops rtnl_class_ops = { + .co_name = "route/class", + .co_hdrsize = sizeof(struct tcmsg), + .co_msgtypes = { + { RTM_NEWTCLASS, NL_ACT_NEW, "new" }, + { RTM_DELTCLASS, NL_ACT_DEL, "del" }, + { RTM_GETTCLASS, NL_ACT_GET, "get" }, + END_OF_MSGTYPES_LIST, + }, + .co_protocol = NETLINK_ROUTE, + .co_request_update = &class_request_update, + .co_msg_parser = &class_msg_parser, + .co_obj_ops = &class_obj_ops, +}; + +static void __init class_init(void) +{ + rtnl_tc_type_register(&class_ops); + nl_cache_mngt_register(&rtnl_class_ops); +} + +static void __exit class_exit(void) +{ + nl_cache_mngt_unregister(&rtnl_class_ops); + rtnl_tc_type_unregister(&class_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/classid.c b/libnetwork/libnl3/lib/route/classid.c new file mode 100644 index 0000000..abed244 --- /dev/null +++ b/libnetwork/libnl3/lib/route/classid.c @@ -0,0 +1,441 @@ +/* + * lib/route/classid.c ClassID Management + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf + */ + +/** + * @ingroup tc + * @defgroup classid ClassID Management + * @{ + */ + +#include +#include +#include +#include +#include + +struct classid_map +{ + uint32_t classid; + char * name; + struct nl_list_head name_list; +}; + +#define CLASSID_NAME_HT_SIZ 256 + +static struct nl_list_head tbl_name[CLASSID_NAME_HT_SIZ]; + +static void *id_root = NULL; + +static int compare_id(const void *pa, const void *pb) +{ + const struct classid_map *ma = pa; + const struct classid_map *mb = pb; + + if (ma->classid < mb->classid) + return -1; + + if (ma->classid > mb->classid) + return 1; + + return 0; +} + +/* djb2 */ +static unsigned int classid_tbl_hash(const char *str) +{ + unsigned long hash = 5381; + int c; + + while ((c = *str++)) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + + return hash % CLASSID_NAME_HT_SIZ; +} + +static int classid_lookup(const char *name, uint32_t *result) +{ + struct classid_map *map; + int n = classid_tbl_hash(name); + + nl_list_for_each_entry(map, &tbl_name[n], name_list) { + if (!strcasecmp(map->name, name)) { + *result = map->classid; + return 0; + } + } + + return -NLE_OBJ_NOTFOUND; +} + +static char *name_lookup(const uint32_t classid) +{ + void *res; + struct classid_map cm = { + .classid = classid, + .name = "search entry", + }; + + if ((res = tfind(&cm, &id_root, &compare_id))) + return (*(struct classid_map **) res)->name; + + return NULL; +} + +/** + * @name Traffic Control Handle Translations + * @{ + */ + +/** + * Convert a traffic control handle to a character string (Reentrant). + * @arg handle traffic control handle + * @arg buf destination buffer + * @arg len buffer length + * + * Converts a tarffic control handle to a character string in the + * form of \c MAJ:MIN and stores it in the specified destination buffer. + * + * @return The destination buffer or the type encoded in hexidecimal + * form if no match was found. + */ +char *rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len) +{ + if (TC_H_ROOT == handle) + snprintf(buf, len, "root"); + else if (TC_H_UNSPEC == handle) + snprintf(buf, len, "none"); + else if (TC_H_INGRESS == handle) + snprintf(buf, len, "ingress"); + else { + char *name; + + if ((name = name_lookup(handle))) + snprintf(buf, len, "%s", name); + else if (0 == TC_H_MAJ(handle)) + snprintf(buf, len, ":%x", TC_H_MIN(handle)); + else if (0 == TC_H_MIN(handle)) + snprintf(buf, len, "%x:", TC_H_MAJ(handle) >> 16); + else + snprintf(buf, len, "%x:%x", + TC_H_MAJ(handle) >> 16, TC_H_MIN(handle)); + } + + return buf; +} + +/** + * Convert a charactering strint to a traffic control handle + * @arg str traffic control handle as character string + * @arg res destination buffer + * + * Converts the provided character string specifying a traffic + * control handle to the corresponding numeric value. + * + * The handle must be provided in one of the following formats: + * - NAME + * - root + * - none + * - MAJ: + * - :MIN + * - NAME:MIN + * - MAJ:MIN + * - MAJMIN + * + * @return 0 on success or a negative error code + */ +int rtnl_tc_str2handle(const char *str, uint32_t *res) +{ + char *colon, *end; + uint32_t h, err; + + if (!strcasecmp(str, "root")) { + *res = TC_H_ROOT; + return 0; + } + + if (!strcasecmp(str, "none")) { + *res = TC_H_UNSPEC; + return 0; + } + + h = strtoul(str, &colon, 16); + + /* MAJ is not a number */ + if (colon == str) { +not_a_number: + if (*colon == ':') { + /* :YYYY */ + h = 0; + } else { + size_t len; + char name[64] = { 0 }; + + if (!(colon = strpbrk(str, ":"))) { + /* NAME */ + return classid_lookup(str, res); + } else { + /* NAME:YYYY */ + len = colon - str; + if (len >= sizeof(name)) + return -NLE_INVAL; + + memcpy(name, str, len); + + if ((err = classid_lookup(name, &h)) < 0) + return err; + + /* Name must point to a qdisc alias */ + if (TC_H_MIN(h)) + return -NLE_INVAL; + + /* NAME: is not allowed */ + if (colon[1] == '\0') + return -NLE_INVAL; + + goto update; + } + } + } + + if (':' == *colon) { + /* check if we would lose bits */ + if (TC_H_MAJ(h)) + return -NLE_RANGE; + h <<= 16; + + if ('\0' == colon[1]) { + /* XXXX: */ + *res = h; + } else { + /* XXXX:YYYY */ + uint32_t l; + +update: + l = strtoul(colon+1, &end, 16); + + /* check if we overlap with major part */ + if (TC_H_MAJ(l)) + return -NLE_RANGE; + + if ('\0' != *end) + return -NLE_INVAL; + + *res = (h | l); + } + } else if ('\0' == *colon) { + /* XXXXYYYY */ + *res = h; + } else + goto not_a_number; + + return 0; +} + +static void free_nothing(void *arg) +{ +} + +static void classid_map_free(struct classid_map *map) +{ + if (!map) + return; + + free(map->name); + free(map); +} + +static void clear_hashtable(void) +{ + int i; + + for (i = 0; i < CLASSID_NAME_HT_SIZ; i++) { + struct classid_map *map, *n; + + nl_list_for_each_entry_safe(map, n, &tbl_name[i], name_list) + classid_map_free(map); + + nl_init_list_head(&tbl_name[i]); + + } + + if (id_root) { + tdestroy(&id_root, &free_nothing); + id_root = NULL; + } +} + +static int classid_map_add(uint32_t classid, const char *name) +{ + struct classid_map *map; + int n; + + if (!(map = calloc(1, sizeof(*map)))) + return -NLE_NOMEM; + + map->classid = classid; + map->name = strdup(name); + + n = classid_tbl_hash(map->name); + nl_list_add_tail(&map->name_list, &tbl_name[n]); + + if (!tsearch((void *) map, &id_root, &compare_id)) { + classid_map_free(map); + return -NLE_NOMEM; + } + + return 0; +} + +/** + * (Re-)read classid file + * + * Rereads the contents of the classid file (typically found at the location + * /etc/libnl/classid) and refreshes the classid maps. + * + * @return 0 on success or a negative error code. + */ +int rtnl_tc_read_classid_file(void) +{ + static time_t last_read; + struct stat st = {0}; + char buf[256], *path; + FILE *fd; + int err; + + if (build_sysconf_path(&path, "classid") < 0) + return -NLE_NOMEM; + + /* if stat fails, just (re-)read the file */ + if (stat(path, &st) == 0) { + /* Don't re-read file if file is unchanged */ + if (last_read == st.st_mtime) { + err = 0; + goto errout; + } + } + + if (!(fd = fopen(path, "r"))) { + err = -nl_syserr2nlerr(errno); + goto errout; + } + + clear_hashtable(); + + while (fgets(buf, sizeof(buf), fd)) { + uint32_t classid; + char *ptr, *tok; + + /* ignore comments and empty lines */ + if (*buf == '#' || *buf == '\n' || *buf == '\r') + continue; + + /* token 1 */ + if (!(tok = strtok_r(buf, " \t", &ptr))) { + err = -NLE_INVAL; + goto errout_close; + } + + if ((err = rtnl_tc_str2handle(tok, &classid)) < 0) + goto errout_close; + + if (!(tok = strtok_r(NULL, " \t\n\r#", &ptr))) { + err = -NLE_INVAL; + goto errout_close; + } + + if ((err = classid_map_add(classid, tok)) < 0) + goto errout_close; + } + + err = 0; + last_read = st.st_mtime; + +errout_close: + fclose(fd); +errout: + free(path); + + return err; + +} + +int rtnl_classid_generate(const char *name, uint32_t *result, uint32_t parent) +{ + static uint32_t base = 0x4000 << 16; + uint32_t classid; + char *path; + FILE *fd; + int err = 0; + + if (parent == TC_H_ROOT || parent == TC_H_INGRESS) { + do { + base += (1 << 16); + if (base == TC_H_MAJ(TC_H_ROOT)) + base = 0x4000 << 16; + } while (name_lookup(base)); + + classid = base; + } else { + classid = TC_H_MAJ(parent); + do { + if (TC_H_MIN(++classid) == TC_H_MIN(TC_H_ROOT)) + return -NLE_RANGE; + } while (name_lookup(classid)); + } + + NL_DBG(2, "Generated new classid %#x\n", classid); + + if (build_sysconf_path(&path, "classid") < 0) + return -NLE_NOMEM; + + if (!(fd = fopen(path, "a"))) { + err = -nl_syserr2nlerr(errno); + goto errout; + } + + fprintf(fd, "%x:", TC_H_MAJ(classid) >> 16); + if (TC_H_MIN(classid)) + fprintf(fd, "%x", TC_H_MIN(classid)); + fprintf(fd, "\t\t\t%s\n", name); + + fclose(fd); + + if ((err = classid_map_add(classid, name)) < 0) { + /* + * Error adding classid map, re-read classid file is best + * option here. It is likely to fail as well but better + * than nothing, entry was added to the file already anyway. + */ + rtnl_tc_read_classid_file(); + } + + *result = classid; + err = 0; +errout: + free(path); + + return err; +} + +/** @} */ + +static void __init classid_init(void) +{ + int err, i; + + for (i = 0; i < CLASSID_NAME_HT_SIZ; i++) + nl_init_list_head(&tbl_name[i]); + + if ((err = rtnl_tc_read_classid_file()) < 0) + fprintf(stderr, "Failed to read classid file: %s\n", nl_geterror(err)); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/cls.c b/libnetwork/libnl3/lib/route/cls.c new file mode 100644 index 0000000..fb2e9be --- /dev/null +++ b/libnetwork/libnl3/lib/route/cls.c @@ -0,0 +1,441 @@ +/* + * lib/route/classifier.c Classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +/** + * @ingroup tc + * @defgroup cls Classifiers + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define CLS_ATTR_PRIO (TCA_ATTR_MAX << 1) +#define CLS_ATTR_PROTOCOL (TCA_ATTR_MAX << 2) +/** @endcond */ + +static struct nl_object_ops cls_obj_ops; +static struct nl_cache_ops rtnl_cls_ops; + + +static int cls_build(struct rtnl_cls *cls, int type, int flags, + struct nl_msg **result) +{ + int err, prio, proto; + struct tcmsg *tchdr; + int required = TCA_ATTR_IFINDEX; + + if ((cls->ce_mask & required) != required) { + APPBUG("ifindex must be specified"); + return -NLE_MISSING_ATTR; + } + + err = rtnl_tc_msg_build(TC_CAST(cls), type, flags, result); + if (err < 0) + return err; + + tchdr = nlmsg_data(nlmsg_hdr(*result)); + prio = rtnl_cls_get_prio(cls); + proto = rtnl_cls_get_protocol(cls); + tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto)); + + return 0; +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct rtnl_cls *rtnl_cls_alloc(void) +{ + struct rtnl_tc *tc; + + tc = TC_CAST(nl_object_alloc(&cls_obj_ops)); + if (tc) + tc->tc_type = RTNL_TC_TYPE_CLS; + + return (struct rtnl_cls *) tc; +} + +void rtnl_cls_put(struct rtnl_cls *cls) +{ + nl_object_put((struct nl_object *) cls); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void rtnl_cls_set_prio(struct rtnl_cls *cls, uint16_t prio) +{ + cls->c_prio = prio; + cls->ce_mask |= CLS_ATTR_PRIO; +} + +uint16_t rtnl_cls_get_prio(struct rtnl_cls *cls) +{ + if (cls->ce_mask & CLS_ATTR_PRIO) + return cls->c_prio; + else + return 0; +} + +void rtnl_cls_set_protocol(struct rtnl_cls *cls, uint16_t protocol) +{ + cls->c_protocol = protocol; + cls->ce_mask |= CLS_ATTR_PROTOCOL; +} + +uint16_t rtnl_cls_get_protocol(struct rtnl_cls *cls) +{ + if (cls->ce_mask & CLS_ATTR_PROTOCOL) + return cls->c_protocol; + else + return ETH_P_ALL; +} + +/** @} */ + + +/** + * @name Addition/Modification/Deletion + * @{ + */ + +/** + * Build a netlink message requesting the addition of a classifier + * @arg cls Classifier to add + * @arg flags Additional netlink message flags + * @arg result Pointer to store resulting netlink message + * + * The behaviour of this function is identical to rtnl_cls_add() with + * the exception that it will not send the message but return it int the + * provided return pointer instead. + * + * @see rtnl_cls_add() + * + * @return 0 on success or a negative error code. + */ +int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags, + struct nl_msg **result) +{ + if (!(flags & NLM_F_CREATE) && !(cls->ce_mask & CLS_ATTR_PRIO)) { + APPBUG("prio must be specified if not a new classifier"); + return -NLE_MISSING_ATTR; + } + + return cls_build(cls, RTM_NEWTFILTER, flags, result); +} + +/** + * Add/Update classifier + * @arg sk Netlink socket + * @arg cls Classifier to add/update + * @arg flags Additional netlink message flags + * + * Builds a \c RTM_NEWTFILTER netlink message requesting the addition + * of a new classifier and sends the message to the kernel. The + * configuration of the classifier is derived from the attributes of + * the specified traffic class. + * + * The following flags may be specified: + * - \c NLM_F_CREATE: Create classifier if it does not exist, + * otherwise -NLE_OBJ_NOTFOUND is returned. + * - \c NLM_F_EXCL: Return -NLE_EXISTS if a classifier with + * matching handle exists already. + * + * Existing classifiers with matching handles will be updated, unless + * the flag \c NLM_F_EXCL is specified. If no matching classifier + * exists, it will be created if the flag \c NLM_F_CREATE is set, + * otherwise the error -NLE_OBJ_NOTFOUND is returned. + * + * If the parent qdisc does not support classes, the error + * \c NLE_OPNOTSUPP is returned. + * + * After sending, the function will wait for the ACK or an eventual + * error message to be received and will therefore block until the + * operation has been completed. + * + * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause + * this function to return immediately after sending. In this case, + * it is the responsibility of the caller to handle any error + * messages returned. + * + * @return 0 on success or a negative error code. + */ +int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_cls_build_add_request(cls, flags, &msg)) < 0) + return err; + + return nl_send_sync(sk, msg); +} + +/** + * Build a netlink message to change classifier attributes + * @arg cls classifier to change + * @arg flags additional netlink message flags + * @arg result Pointer to store resulting message. + * + * Builds a new netlink message requesting a change of a neigh + * attributes. The netlink message header isn't fully equipped with + * all relevant fields and must thus be sent out via nl_send_auto_complete() + * or supplemented as needed. + * + * @return 0 on success or a negative error code. + */ +int rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags, + struct nl_msg **result) +{ + return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags, result); +} + +/** + * Change a classifier + * @arg sk Netlink socket. + * @arg cls classifier to change + * @arg flags additional netlink message flags + * + * Builds a netlink message by calling rtnl_cls_build_change_request(), + * sends the request to the kernel and waits for the next ACK to be + * received and thus blocks until the request has been processed. + * + * @return 0 on sucess or a negative error if an error occured. + */ +int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_cls_build_change_request(cls, flags, &msg)) < 0) + return err; + + return nl_send_sync(sk, msg); +} + +/** + * Build netlink message requesting the deletion of a classifier + * @arg cls Classifier to delete + * @arg flags Additional netlink message flags + * @arg result Pointer to store resulting netlink message + * + * The behaviour of this function is identical to rtnl_cls_delete() with + * the exception that it will not send the message but return it in the + * provided return pointer instead. + * + * @see rtnl_cls_delete() + * + * @return 0 on success or a negative error code. + */ +int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags, + struct nl_msg **result) +{ + int required = CLS_ATTR_PRIO; + + if ((cls->ce_mask & required) != required) { + APPBUG("prio must be specified"); + return -NLE_MISSING_ATTR; + } + + return cls_build(cls, RTM_DELTFILTER, flags, result); +} + +/** + * Delete classifier + * @arg sk Netlink socket + * @arg cls Classifier to delete + * @arg flags Additional netlink message flags + * + * Builds a \c RTM_DELTFILTER netlink message requesting the deletion + * of a classifier and sends the message to the kernel. + * + * The message is constructed out of the following attributes: + * - \c ifindex (required) + * - \c prio (required) + * - \c protocol (required) + * - \c handle (required) + * - \c parent (optional, if not specified parent equals root-qdisc) + * - \c kind (optional, must match if provided) + * + * All other classifier attributes including all class type specific + * attributes are ignored. + * + * After sending, the function will wait for the ACK or an eventual + * error message to be received and will therefore block until the + * operation has been completed. + * + * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause + * this function to return immediately after sending. In this case, + * it is the responsibility of the caller to handle any error + * messages returned. + * + * @return 0 on success or a negative error code. + */ +int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0) + return err; + + return nl_send_sync(sk, msg); +} + +/** @} */ + +/** + * @name Cache Related Functions + * @{ + */ + +/** + * Allocate a cache and fill it with all configured classifiers + * @arg sk Netlink socket + * @arg ifindex Interface index of the network device + * @arg parent Parent qdisc/traffic class class + * @arg result Pointer to store the created cache + * + * Allocates a new classifier cache and fills it with a list of all + * configured classifier attached to the specified parent qdisc/traffic + * class on the specified network device. Release the cache with + * nl_cache_free(). + * + * @return 0 on success or a negative error code. + */ +int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent, struct nl_cache **result) +{ + struct nl_cache * cache; + int err; + + if (!(cache = nl_cache_alloc(&rtnl_cls_ops))) + return -NLE_NOMEM; + + cache->c_iarg1 = ifindex; + cache->c_iarg2 = parent; + + if (sk && (err = nl_cache_refill(sk, cache)) < 0) { + nl_cache_free(cache); + return err; + } + + *result = cache; + return 0; +} + +/** @} */ + +static void cls_dump_line(struct rtnl_tc *tc, struct nl_dump_params *p) +{ + struct rtnl_cls *cls = (struct rtnl_cls *) tc; + char buf[32]; + + nl_dump(p, " prio %u protocol %s", cls->c_prio, + nl_ether_proto2str(cls->c_protocol, buf, sizeof(buf))); +} + +static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *nlh, struct nl_parser_param *pp) +{ + struct rtnl_cls *cls; + int err; + + if (!(cls = rtnl_cls_alloc())) + return -NLE_NOMEM; + + if ((err = rtnl_tc_msg_parse(nlh, TC_CAST(cls))) < 0) + goto errout; + + cls->c_prio = TC_H_MAJ(cls->c_info) >> 16; + cls->c_protocol = ntohs(TC_H_MIN(cls->c_info)); + + err = pp->pp_cb(OBJ_CAST(cls), pp); +errout: + rtnl_cls_put(cls); + + return err; +} + +static int cls_request_update(struct nl_cache *cache, struct nl_sock *sk) +{ + struct tcmsg tchdr = { + .tcm_family = AF_UNSPEC, + .tcm_ifindex = cache->c_iarg1, + .tcm_parent = cache->c_iarg2, + }; + + return nl_send_simple(sk, RTM_GETTFILTER, NLM_F_DUMP, &tchdr, + sizeof(tchdr)); +} + +static struct rtnl_tc_type_ops cls_ops = { + .tt_type = RTNL_TC_TYPE_CLS, + .tt_dump_prefix = "cls", + .tt_dump = { + [NL_DUMP_LINE] = cls_dump_line, + }, +}; + +static struct nl_cache_ops rtnl_cls_ops = { + .co_name = "route/cls", + .co_hdrsize = sizeof(struct tcmsg), + .co_msgtypes = { + { RTM_NEWTFILTER, NL_ACT_NEW, "new" }, + { RTM_DELTFILTER, NL_ACT_DEL, "del" }, + { RTM_GETTFILTER, NL_ACT_GET, "get" }, + END_OF_MSGTYPES_LIST, + }, + .co_protocol = NETLINK_ROUTE, + .co_request_update = cls_request_update, + .co_msg_parser = cls_msg_parser, + .co_obj_ops = &cls_obj_ops, +}; + +static struct nl_object_ops cls_obj_ops = { + .oo_name = "route/cls", + .oo_size = sizeof(struct rtnl_cls), + .oo_free_data = rtnl_tc_free_data, + .oo_clone = rtnl_tc_clone, + .oo_dump = { + [NL_DUMP_LINE] = rtnl_tc_dump_line, + [NL_DUMP_DETAILS] = rtnl_tc_dump_details, + [NL_DUMP_STATS] = rtnl_tc_dump_stats, + }, + .oo_compare = rtnl_tc_compare, + .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE), +}; + +static void __init cls_init(void) +{ + rtnl_tc_type_register(&cls_ops); + nl_cache_mngt_register(&rtnl_cls_ops); +} + +static void __exit cls_exit(void) +{ + nl_cache_mngt_unregister(&rtnl_cls_ops); + rtnl_tc_type_unregister(&cls_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/cls/.dirstamp b/libnetwork/libnl3/lib/route/cls/.dirstamp new file mode 100644 index 0000000..e69de29 diff --git a/libnetwork/libnl3/lib/route/cls/basic.c b/libnetwork/libnl3/lib/route/cls/basic.c new file mode 100644 index 0000000..9d7710a --- /dev/null +++ b/libnetwork/libnl3/lib/route/cls/basic.c @@ -0,0 +1,229 @@ +/* + * lib/route/cls/basic.c Basic Classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2011 Thomas Graf + */ + +/** + * @ingroup cls + * @defgroup cls_basic Basic Classifier + * + * @par Introduction + * The basic classifier is the simplest form of a classifier. It does + * not have any special classification capabilities, instead it can be + * used to classify exclusively based on extended matches or to + * create a "catch-all" filter. + * + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include + +struct rtnl_basic +{ + uint32_t b_target; + struct rtnl_ematch_tree * b_ematch; + int b_mask; +}; + +/** @cond SKIP */ +#define BASIC_ATTR_TARGET 0x001 +#define BASIC_ATTR_EMATCH 0x002 +/** @endcond */ + +static struct nla_policy basic_policy[TCA_BASIC_MAX+1] = { + [TCA_BASIC_CLASSID] = { .type = NLA_U32 }, + [TCA_BASIC_EMATCHES] = { .type = NLA_NESTED }, +}; + +static int basic_clone(void *_dst, void *_src) +{ + return -NLE_OPNOTSUPP; +} + +static void basic_free_data(struct rtnl_tc *tc, void *data) +{ + struct rtnl_basic *b = data; + + if (!b) + return; + + rtnl_ematch_tree_free(b->b_ematch); +} + +static int basic_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct nlattr *tb[TCA_BASIC_MAX + 1]; + struct rtnl_basic *b = data; + int err; + + err = tca_parse(tb, TCA_BASIC_MAX, tc, basic_policy); + if (err < 0) + return err; + + if (tb[TCA_BASIC_CLASSID]) { + b->b_target = nla_get_u32(tb[TCA_BASIC_CLASSID]); + b->b_mask |= BASIC_ATTR_TARGET; + } + + if (tb[TCA_BASIC_EMATCHES]) { + if ((err = rtnl_ematch_parse_attr(tb[TCA_BASIC_EMATCHES], + &b->b_ematch)) < 0) + return err; + + if (b->b_ematch) + b->b_mask |= BASIC_ATTR_EMATCH; + } + + return 0; +} + +static void basic_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_basic *b = data; + char buf[32]; + + if (!b) + return; + + if (b->b_mask & BASIC_ATTR_EMATCH) + nl_dump(p, " ematch"); + else + nl_dump(p, " match-all"); + + if (b->b_mask & BASIC_ATTR_TARGET) + nl_dump(p, " target %s", + rtnl_tc_handle2str(b->b_target, buf, sizeof(buf))); +} + +static void basic_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_basic *b = data; + + if (!b) + return; + + if (b->b_mask & BASIC_ATTR_EMATCH) { + nl_dump_line(p, " ematch "); + rtnl_ematch_tree_dump(b->b_ematch, p); + } else + nl_dump(p, "no options.\n"); +} + +static int basic_msg_fill(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) +{ + struct rtnl_basic *b = data; + + if (!b) + return 0; + + if (!(b->b_mask & BASIC_ATTR_TARGET)) + return -NLE_MISSING_ATTR; + + NLA_PUT_U32(msg, TCA_BASIC_CLASSID, b->b_target); + + if (b->b_mask & BASIC_ATTR_EMATCH && + rtnl_ematch_fill_attr(msg, TCA_BASIC_EMATCHES, b->b_ematch) < 0) + goto nla_put_failure; + + return 0; + +nla_put_failure: + return -NLE_NOMEM; +} + +/** + * @name Attribute Modifications + * @{ + */ + +void rtnl_basic_set_target(struct rtnl_cls *cls, uint32_t target) +{ + struct rtnl_basic *b; + + if (!(b = rtnl_tc_data(TC_CAST(cls)))) + return; + + b->b_target = target; + b->b_mask |= BASIC_ATTR_TARGET; +} + +uint32_t rtnl_basic_get_target(struct rtnl_cls *cls) +{ + struct rtnl_basic *b; + + if (!(b = rtnl_tc_data(TC_CAST(cls)))) + return 0; + + return b->b_target; +} + +void rtnl_basic_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree) +{ + struct rtnl_basic *b; + + if (!(b = rtnl_tc_data(TC_CAST(cls)))) + return; + + if (b->b_ematch) { + rtnl_ematch_tree_free(b->b_ematch); + b->b_mask &= ~BASIC_ATTR_EMATCH; + } + + b->b_ematch = tree; + + if (tree) + b->b_mask |= BASIC_ATTR_EMATCH; +} + +struct rtnl_ematch_tree *rtnl_basic_get_ematch(struct rtnl_cls *cls) +{ + struct rtnl_basic *b; + + if (!(b = rtnl_tc_data(TC_CAST(cls)))) + return NULL; + + return b->b_ematch; +} + +/** @} */ + +static struct rtnl_tc_ops basic_ops = { + .to_kind = "basic", + .to_type = RTNL_TC_TYPE_CLS, + .to_size = sizeof(struct rtnl_basic), + .to_msg_parser = basic_msg_parser, + .to_clone = basic_clone, + .to_free_data = basic_free_data, + .to_msg_fill = basic_msg_fill, + .to_dump = { + [NL_DUMP_LINE] = basic_dump_line, + [NL_DUMP_DETAILS] = basic_dump_details, + }, +}; + +static void __init basic_init(void) +{ + rtnl_tc_register(&basic_ops); +} + +static void __exit basic_exit(void) +{ + rtnl_tc_unregister(&basic_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/cls/cgroup.c b/libnetwork/libnl3/lib/route/cls/cgroup.c new file mode 100644 index 0000000..230863b --- /dev/null +++ b/libnetwork/libnl3/lib/route/cls/cgroup.c @@ -0,0 +1,189 @@ +/* + * lib/route/cls/cgroup.c Control Groups Classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2009-2011 Thomas Graf + */ + +/** + * @ingroup cls + * @defgroup cls_cgroup Control Groups Classifier + * + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define CGROUP_ATTR_EMATCH 0x001 +/** @endcond */ + +static struct nla_policy cgroup_policy[TCA_CGROUP_MAX+1] = { + [TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED }, +}; + +static int cgroup_clone(void *dst, void *src) +{ + return -NLE_OPNOTSUPP; +} + +static void cgroup_free_data(struct rtnl_tc *tc, void *data) +{ + struct rtnl_cgroup *c = data; + + if (!c) + return; + + rtnl_ematch_tree_free(c->cg_ematch); +} + +static int cgroup_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct nlattr *tb[TCA_CGROUP_MAX + 1]; + struct rtnl_cgroup *c = data; + int err; + + err = tca_parse(tb, TCA_CGROUP_MAX, tc, cgroup_policy); + if (err < 0) + return err; + + if (tb[TCA_CGROUP_EMATCHES]) { + if ((err = rtnl_ematch_parse_attr(tb[TCA_CGROUP_EMATCHES], + &c->cg_ematch)) < 0) + return err; + c->cg_mask |= CGROUP_ATTR_EMATCH; + } + +#if 0 + TODO: + TCA_CGROUP_ACT, + TCA_CGROUP_POLICE, +#endif + + return 0; +} + +static void cgroup_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_cgroup *c = data; + + if (!c) + return; + + if (c->cg_mask & CGROUP_ATTR_EMATCH) + nl_dump(p, " ematch"); + else + nl_dump(p, " match-all"); +} + +static void cgroup_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_cgroup *c = data; + + if (!c) + return; + + if (c->cg_mask & CGROUP_ATTR_EMATCH) { + nl_dump_line(p, " ematch "); + + if (c->cg_ematch) + rtnl_ematch_tree_dump(c->cg_ematch, p); + else + nl_dump(p, ""); + } else + nl_dump(p, "no options"); +} + +static int cgroup_fill_msg(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) +{ + struct rtnl_cgroup *c = data; + + if (!c) + BUG(); + + if (!(tc->ce_mask & TCA_ATTR_HANDLE)) + return -NLE_MISSING_ATTR; + + if (c->cg_mask & CGROUP_ATTR_EMATCH) + return rtnl_ematch_fill_attr(msg, TCA_CGROUP_EMATCHES, + c->cg_ematch); + + return 0; +} + + +/** + * @name Attribute Modifications + * @{ + */ + +void rtnl_cgroup_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree) +{ + struct rtnl_cgroup *c; + + if (!(c = rtnl_tc_data(TC_CAST(cls)))) + BUG(); + + if (c->cg_ematch) { + rtnl_ematch_tree_free(c->cg_ematch); + c->cg_mask &= ~CGROUP_ATTR_EMATCH; + } + + c->cg_ematch = tree; + + if (tree) + c->cg_mask |= CGROUP_ATTR_EMATCH; +} + +struct rtnl_ematch_tree *rtnl_cgroup_get_ematch(struct rtnl_cls *cls) +{ + struct rtnl_cgroup *c; + + if (!(c = rtnl_tc_data(TC_CAST(cls)))) + BUG(); + + return c->cg_ematch; +} + +/** @} */ + +static struct rtnl_tc_ops cgroup_ops = { + .to_kind = "cgroup", + .to_type = RTNL_TC_TYPE_CLS, + .to_size = sizeof(struct rtnl_cgroup), + .to_clone = cgroup_clone, + .to_msg_parser = cgroup_msg_parser, + .to_free_data = cgroup_free_data, + .to_msg_fill = cgroup_fill_msg, + .to_dump = { + [NL_DUMP_LINE] = cgroup_dump_line, + [NL_DUMP_DETAILS] = cgroup_dump_details, + }, +}; + +static void __init cgroup_init(void) +{ + rtnl_tc_register(&cgroup_ops); +} + +static void __exit cgroup_exit(void) +{ + rtnl_tc_unregister(&cgroup_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/cls/ematch.c b/libnetwork/libnl3/lib/route/cls/ematch.c new file mode 100644 index 0000000..8c9c3dd --- /dev/null +++ b/libnetwork/libnl3/lib/route/cls/ematch.c @@ -0,0 +1,701 @@ +/* + * lib/route/cls/ematch.c Extended Matches + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2010 Thomas Graf + */ + +/** + * @ingroup cls + * @defgroup ematch Extended Match + * + * @{ + */ + +#include +#include +#include +#include +#include +#include + +#include "ematch_syntax.h" +#include "ematch_grammar.h" + +/** + * @name Module API + * @{ + */ + +static NL_LIST_HEAD(ematch_ops_list); + +/** + * Register ematch module + * @arg ops Module operations. + * + * This function must be called by each ematch module at initialization + * time. It registers the calling module as available module. + * + * @return 0 on success or a negative error code. + */ +int rtnl_ematch_register(struct rtnl_ematch_ops *ops) +{ + if (rtnl_ematch_lookup_ops(ops->eo_kind)) + return -NLE_EXIST; + + NL_DBG(1, "ematch module \"%s\" registered\n", ops->eo_name); + + nl_list_add_tail(&ops->eo_list, &ematch_ops_list); + + return 0; +} + +/** + * Lookup ematch module by identification number. + * @arg kind Module kind. + * + * Searches the list of registered ematch modules for match and returns it. + * + * @return Module operations or NULL if not found. + */ +struct rtnl_ematch_ops *rtnl_ematch_lookup_ops(int kind) +{ + struct rtnl_ematch_ops *ops; + + nl_list_for_each_entry(ops, &ematch_ops_list, eo_list) + if (ops->eo_kind == kind) + return ops; + + return NULL; +} + +/** + * Lookup ematch module by name + * @arg name Name of ematch module. + * + * Searches the list of registered ematch modules for a match and returns it. + * + * @return Module operations or NULL if not fuond. + */ +struct rtnl_ematch_ops *rtnl_ematch_lookup_ops_by_name(const char *name) +{ + struct rtnl_ematch_ops *ops; + + nl_list_for_each_entry(ops, &ematch_ops_list, eo_list) + if (!strcasecmp(ops->eo_name, name)) + return ops; + + return NULL; +} + +/** @} */ + +/** + * @name Match + */ + +/** + * Allocate ematch object. + * + * Allocates and initializes an ematch object. + * + * @return New ematch object or NULL. + */ +struct rtnl_ematch *rtnl_ematch_alloc(void) +{ + struct rtnl_ematch *e; + + if (!(e = calloc(1, sizeof(*e)))) + return NULL; + + NL_DBG(2, "allocated ematch %p\n", e); + + NL_INIT_LIST_HEAD(&e->e_list); + NL_INIT_LIST_HEAD(&e->e_childs); + + return e; +} + +/** + * Add ematch to the end of the parent's list of children. + * @arg parent parent ematch object + * @arg child ematch object to be added to parent + * + * The parent must be a container ematch. + */ +int rtnl_ematch_add_child(struct rtnl_ematch *parent, + struct rtnl_ematch *child) +{ + if (parent->e_kind != TCF_EM_CONTAINER) + return -NLE_OPNOTSUPP; + + NL_DBG(2, "added ematch %p \"%s\" to container %p\n", + child, child->e_ops->eo_name, parent); + + nl_list_add_tail(&child->e_list, &parent->e_childs); + + return 0; +} + +/** + * Remove ematch from the list of ematches it is linked to. + * @arg ematch ematch object + */ +void rtnl_ematch_unlink(struct rtnl_ematch *ematch) +{ + NL_DBG(2, "unlinked ematch %p from any lists\n", ematch); + + if (!nl_list_empty(&ematch->e_childs)) + NL_DBG(1, "warning: ematch %p with childs was unlinked\n", + ematch); + + nl_list_del(&ematch->e_list); + nl_init_list_head(&ematch->e_list); +} + +void rtnl_ematch_free(struct rtnl_ematch *ematch) +{ + NL_DBG(2, "freed ematch %p\n", ematch); + rtnl_ematch_unlink(ematch); + free(ematch->e_data); + free(ematch); +} + +int rtnl_ematch_set_ops(struct rtnl_ematch *ematch, struct rtnl_ematch_ops *ops) +{ + if (ematch->e_ops) + return -NLE_EXIST; + + ematch->e_ops = ops; + ematch->e_kind = ops->eo_kind; + + if (ops->eo_datalen) { + ematch->e_data = calloc(1, ops->eo_datalen); + if (!ematch->e_data) + return -NLE_NOMEM; + + ematch->e_datalen = ops->eo_datalen; + } + + return 0; +} + +int rtnl_ematch_set_kind(struct rtnl_ematch *ematch, uint16_t kind) +{ + struct rtnl_ematch_ops *ops; + + if (ematch->e_kind) + return -NLE_EXIST; + + ematch->e_kind = kind; + + if ((ops = rtnl_ematch_lookup_ops(kind))) + rtnl_ematch_set_ops(ematch, ops); + + return 0; +} + +int rtnl_ematch_set_name(struct rtnl_ematch *ematch, const char *name) +{ + struct rtnl_ematch_ops *ops; + + if (ematch->e_kind) + return -NLE_EXIST; + + if (!(ops = rtnl_ematch_lookup_ops_by_name(name))) + return -NLE_OPNOTSUPP; + + rtnl_ematch_set_ops(ematch, ops); + + return 0; +} + +void rtnl_ematch_set_flags(struct rtnl_ematch *ematch, uint16_t flags) +{ + ematch->e_flags |= flags; +} + +void rtnl_ematch_unset_flags(struct rtnl_ematch *ematch, uint16_t flags) +{ + ematch->e_flags &= ~flags; +} + +uint16_t rtnl_ematch_get_flags(struct rtnl_ematch *ematch) +{ + return ematch->e_flags; +} + +void *rtnl_ematch_data(struct rtnl_ematch *ematch) +{ + return ematch->e_data; +} + +/** @} */ + +/** + * @name Tree + */ + +/** + * Allocate ematch tree object + * @arg progid program id + */ +struct rtnl_ematch_tree *rtnl_ematch_tree_alloc(uint16_t progid) +{ + struct rtnl_ematch_tree *tree; + + if (!(tree = calloc(1, sizeof(*tree)))) + return NULL; + + NL_INIT_LIST_HEAD(&tree->et_list); + tree->et_progid = progid; + + NL_DBG(2, "allocated new ematch tree %p, progid=%u\n", tree, progid); + + return tree; +} + +static void free_ematch_list(struct nl_list_head *head) +{ + struct rtnl_ematch *pos, *next; + + nl_list_for_each_entry_safe(pos, next, head, e_list) { + if (!nl_list_empty(&pos->e_childs)) + free_ematch_list(&pos->e_childs); + rtnl_ematch_free(pos); + } +} + +/** + * Free ematch tree object + * @arg tree ematch tree object + * + * This function frees the ematch tree and all ematches attached to it. + */ +void rtnl_ematch_tree_free(struct rtnl_ematch_tree *tree) +{ + if (!tree) + return; + + free_ematch_list(&tree->et_list); + free(tree); + + NL_DBG(2, "Freed ematch tree %p\n", tree); +} + +/** + * Add ematch object to the end of the ematch tree + * @arg tree ematch tree object + * @arg ematch ematch object to add + */ +void rtnl_ematch_tree_add(struct rtnl_ematch_tree *tree, + struct rtnl_ematch *ematch) +{ + nl_list_add_tail(&ematch->e_list, &tree->et_list); +} + +static inline uint32_t container_ref(struct rtnl_ematch *ematch) +{ + return *((uint32_t *) rtnl_ematch_data(ematch)); +} + +static int link_tree(struct rtnl_ematch *index[], int nmatches, int pos, + struct nl_list_head *root) +{ + struct rtnl_ematch *ematch; + int i; + + for (i = pos; i < nmatches; i++) { + ematch = index[i]; + + nl_list_add_tail(&ematch->e_list, root); + + if (ematch->e_kind == TCF_EM_CONTAINER) + link_tree(index, nmatches, container_ref(ematch), + &ematch->e_childs); + + if (!(ematch->e_flags & TCF_EM_REL_MASK)) + return 0; + } + + /* Last entry in chain can't possibly have no relation */ + return -NLE_INVAL; +} + +static struct nla_policy tree_policy[TCA_EMATCH_TREE_MAX+1] = { + [TCA_EMATCH_TREE_HDR] = { .minlen=sizeof(struct tcf_ematch_tree_hdr) }, + [TCA_EMATCH_TREE_LIST] = { .type = NLA_NESTED }, +}; + +/** + * Parse ematch netlink attributes + * + * @return 0 on success or a negative error code. + */ +int rtnl_ematch_parse_attr(struct nlattr *attr, struct rtnl_ematch_tree **result) +{ + struct nlattr *a, *tb[TCA_EMATCH_TREE_MAX+1]; + struct tcf_ematch_tree_hdr *thdr; + struct rtnl_ematch_tree *tree; + struct rtnl_ematch **index; + int nmatches = 0, err, remaining; + + NL_DBG(2, "Parsing attribute %p as ematch tree\n", attr); + + err = nla_parse_nested(tb, TCA_EMATCH_TREE_MAX, attr, tree_policy); + if (err < 0) + return err; + + if (!tb[TCA_EMATCH_TREE_HDR]) + return -NLE_MISSING_ATTR; + + thdr = nla_data(tb[TCA_EMATCH_TREE_HDR]); + + /* Ignore empty trees */ + if (thdr->nmatches == 0) { + NL_DBG(2, "Ignoring empty ematch configuration\n"); + return 0; + } + + if (!tb[TCA_EMATCH_TREE_LIST]) + return -NLE_MISSING_ATTR; + + NL_DBG(2, "ematch tree found with nmatches=%u, progid=%u\n", + thdr->nmatches, thdr->progid); + + /* + * Do some basic sanity checking since we will allocate + * index[thdr->nmatches]. Calculate how many ematch headers fit into + * the provided data and make sure nmatches does not exceed it. + */ + if (thdr->nmatches > (nla_len(tb[TCA_EMATCH_TREE_LIST]) / + nla_total_size(sizeof(struct tcf_ematch_hdr)))) + return -NLE_INVAL; + + if (!(index = calloc(thdr->nmatches, sizeof(struct rtnl_ematch *)))) + return -NLE_NOMEM; + + if (!(tree = rtnl_ematch_tree_alloc(thdr->progid))) { + err = -NLE_NOMEM; + goto errout; + } + + nla_for_each_nested(a, tb[TCA_EMATCH_TREE_LIST], remaining) { + struct rtnl_ematch_ops *ops; + struct tcf_ematch_hdr *hdr; + struct rtnl_ematch *ematch; + void *data; + size_t len; + + NL_DBG(3, "parsing ematch attribute %d, len=%u\n", + nmatches+1, nla_len(a)); + + if (nla_len(a) < sizeof(*hdr)) { + err = -NLE_INVAL; + goto errout; + } + + /* Quit as soon as we've parsed more matches than expected */ + if (nmatches >= thdr->nmatches) { + err = -NLE_RANGE; + goto errout; + } + + hdr = nla_data(a); + data = nla_data(a) + NLA_ALIGN(sizeof(*hdr)); + len = nla_len(a) - NLA_ALIGN(sizeof(*hdr)); + + NL_DBG(3, "ematch attribute matchid=%u, kind=%u, flags=%u\n", + hdr->matchid, hdr->kind, hdr->flags); + + /* + * Container matches contain a reference to another sequence + * of matches. Ensure that the reference is within boundries. + */ + if (hdr->kind == TCF_EM_CONTAINER && + *((uint32_t *) data) >= thdr->nmatches) { + err = -NLE_INVAL; + goto errout; + } + + if (!(ematch = rtnl_ematch_alloc())) { + err = -NLE_NOMEM; + goto errout; + } + + ematch->e_id = hdr->matchid; + ematch->e_kind = hdr->kind; + ematch->e_flags = hdr->flags; + + if ((ops = rtnl_ematch_lookup_ops(hdr->kind))) { + if (ops->eo_minlen && len < ops->eo_minlen) { + rtnl_ematch_free(ematch); + err = -NLE_INVAL; + goto errout; + } + + rtnl_ematch_set_ops(ematch, ops); + + if (ops->eo_parse && + (err = ops->eo_parse(ematch, data, len)) < 0) { + rtnl_ematch_free(ematch); + goto errout; + } + } + + NL_DBG(3, "index[%d] = %p\n", nmatches, ematch); + index[nmatches++] = ematch; + } + + if (nmatches != thdr->nmatches) { + err = -NLE_INVAL; + goto errout; + } + + err = link_tree(index, nmatches, 0, &tree->et_list); + if (err < 0) + goto errout; + + free(index); + *result = tree; + + return 0; + +errout: + rtnl_ematch_tree_free(tree); + free(index); + return err; +} + +static void dump_ematch_sequence(struct nl_list_head *head, + struct nl_dump_params *p) +{ + struct rtnl_ematch *match; + + nl_list_for_each_entry(match, head, e_list) { + if (match->e_flags & TCF_EM_INVERT) + nl_dump(p, "!"); + + if (match->e_kind == TCF_EM_CONTAINER) { + nl_dump(p, "("); + dump_ematch_sequence(&match->e_childs, p); + nl_dump(p, ")"); + } else if (!match->e_ops) { + nl_dump(p, "[unknown ematch %d]", match->e_kind); + } else { + if (match->e_ops->eo_dump) + match->e_ops->eo_dump(match, p); + else + nl_dump(p, "[data]"); + } + + switch (match->e_flags & TCF_EM_REL_MASK) { + case TCF_EM_REL_AND: + nl_dump(p, " AND "); + break; + case TCF_EM_REL_OR: + nl_dump(p, " OR "); + break; + default: + /* end of first level ematch sequence */ + return; + } + } +} + +void rtnl_ematch_tree_dump(struct rtnl_ematch_tree *tree, + struct nl_dump_params *p) +{ + if (!tree) + BUG(); + + dump_ematch_sequence(&tree->et_list, p); + nl_dump(p, "\n"); +} + +static int update_container_index(struct nl_list_head *list, int *index) +{ + struct rtnl_ematch *e; + + nl_list_for_each_entry(e, list, e_list) + e->e_index = (*index)++; + + nl_list_for_each_entry(e, list, e_list) { + if (e->e_kind == TCF_EM_CONTAINER) { + int err; + + if (nl_list_empty(&e->e_childs)) + return -NLE_OBJ_NOTFOUND; + + *((uint32_t *) e->e_data) = *index; + + err = update_container_index(&e->e_childs, index); + if (err < 0) + return err; + } + } + + return 0; +} + +static int fill_ematch_sequence(struct nl_msg *msg, struct nl_list_head *list) +{ + struct rtnl_ematch *e; + + nl_list_for_each_entry(e, list, e_list) { + struct tcf_ematch_hdr match = { + .matchid = e->e_id, + .kind = e->e_kind, + .flags = e->e_flags, + }; + struct nlattr *attr; + int err = 0; + + if (!(attr = nla_nest_start(msg, e->e_index + 1))) + return -NLE_NOMEM; + + if (nlmsg_append(msg, &match, sizeof(match), 0) < 0) + return -NLE_NOMEM; + + if (e->e_ops->eo_fill) + err = e->e_ops->eo_fill(e, msg); + else if (e->e_flags & TCF_EM_SIMPLE) + err = nlmsg_append(msg, e->e_data, 4, 0); + else if (e->e_datalen > 0) + err = nlmsg_append(msg, e->e_data, e->e_datalen, 0); + + NL_DBG(3, "msg %p: added ematch [%d] id=%d kind=%d flags=%d\n", + msg, e->e_index, match.matchid, match.kind, match.flags); + + if (err < 0) + return -NLE_NOMEM; + + nla_nest_end(msg, attr); + } + + nl_list_for_each_entry(e, list, e_list) { + if (e->e_kind == TCF_EM_CONTAINER && + fill_ematch_sequence(msg, &e->e_childs) < 0) + return -NLE_NOMEM; + } + + return 0; +} + +int rtnl_ematch_fill_attr(struct nl_msg *msg, int attrid, + struct rtnl_ematch_tree *tree) +{ + struct tcf_ematch_tree_hdr thdr = { + .progid = tree->et_progid, + }; + struct nlattr *list, *topattr; + int err, index = 0; + + /* Assign index number to each ematch to allow for references + * to be made while constructing the sequence of matches. */ + err = update_container_index(&tree->et_list, &index); + if (err < 0) + return err; + + if (!(topattr = nla_nest_start(msg, attrid))) + goto nla_put_failure; + + thdr.nmatches = index; + NLA_PUT(msg, TCA_EMATCH_TREE_HDR, sizeof(thdr), &thdr); + + if (!(list = nla_nest_start(msg, TCA_EMATCH_TREE_LIST))) + goto nla_put_failure; + + if (fill_ematch_sequence(msg, &tree->et_list) < 0) + goto nla_put_failure; + + nla_nest_end(msg, list); + + nla_nest_end(msg, topattr); + + return 0; + +nla_put_failure: + return -NLE_NOMEM; +} + +/** @} */ + +extern int ematch_parse(void *, char **, struct nl_list_head *); + +int rtnl_ematch_parse_expr(const char *expr, char **errp, + struct rtnl_ematch_tree **result) +{ + struct rtnl_ematch_tree *tree; + YY_BUFFER_STATE buf = NULL; + yyscan_t scanner = NULL; + int err; + + NL_DBG(2, "Parsing ematch expression \"%s\"\n", expr); + + if (!(tree = rtnl_ematch_tree_alloc(RTNL_EMATCH_PROGID))) + return -NLE_FAILURE; + + if ((err = ematch_lex_init(&scanner)) < 0) { + err = -NLE_FAILURE; + goto errout; + } + + buf = ematch__scan_string(expr, scanner); + + if ((err = ematch_parse(scanner, errp, &tree->et_list)) != 0) { + ematch__delete_buffer(buf, scanner); + err = -NLE_PARSE_ERR; + goto errout; + } + + if (scanner) + ematch_lex_destroy(scanner); + + *result = tree; + + return 0; + +errout: + if (scanner) + ematch_lex_destroy(scanner); + + rtnl_ematch_tree_free(tree); + + return err; +} + +static const char *layer_txt[] = { + [TCF_LAYER_LINK] = "eth", + [TCF_LAYER_NETWORK] = "ip", + [TCF_LAYER_TRANSPORT] = "tcp", +}; + +char *rtnl_ematch_offset2txt(uint8_t layer, uint16_t offset, char *buf, size_t len) +{ + snprintf(buf, len, "%s+%u", + (layer <= TCF_LAYER_MAX) ? layer_txt[layer] : "?", + offset); + + return buf; +} + +static const char *operand_txt[] = { + [TCF_EM_OPND_EQ] = "=", + [TCF_EM_OPND_LT] = "<", + [TCF_EM_OPND_GT] = ">", +}; + +char *rtnl_ematch_opnd2txt(uint8_t opnd, char *buf, size_t len) +{ + snprintf(buf, len, "%s", + opnd <= ARRAY_SIZE(operand_txt) ? operand_txt[opnd] : "?"); + + return buf; +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/cls/ematch/.dirstamp b/libnetwork/libnl3/lib/route/cls/ematch/.dirstamp new file mode 100644 index 0000000..e69de29 diff --git a/libnetwork/libnl3/lib/route/cls/ematch/cmp.c b/libnetwork/libnl3/lib/route/cls/ematch/cmp.c new file mode 100644 index 0000000..2a1070a --- /dev/null +++ b/libnetwork/libnl3/lib/route/cls/ematch/cmp.c @@ -0,0 +1,93 @@ +/* + * lib/route/cls/ematch/cmp.c Simple packet data comparison ematch + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2010 Thomas Graf + */ + +/** + * @ingroup ematch + * @defgroup em_cmp Simple packet data comparison + * + * @{ + */ + +#include +#include +#include +#include +#include + +void rtnl_ematch_cmp_set(struct rtnl_ematch *e, struct tcf_em_cmp *cfg) +{ + memcpy(rtnl_ematch_data(e), cfg, sizeof(*cfg)); +} + +struct tcf_em_cmp *rtnl_ematch_cmp_get(struct rtnl_ematch *e) +{ + return rtnl_ematch_data(e); +} + +static int cmp_parse(struct rtnl_ematch *e, void *data, size_t len) +{ + memcpy(rtnl_ematch_data(e), data, len); + + return 0; +} + +static const char *align_txt[] = { + [TCF_EM_ALIGN_U8] = "u8", + [TCF_EM_ALIGN_U16] = "u16", + [TCF_EM_ALIGN_U32] = "u32" +}; + +static const char *layer_txt[] = { + [TCF_LAYER_LINK] = "eth", + [TCF_LAYER_NETWORK] = "ip", + [TCF_LAYER_TRANSPORT] = "tcp" +}; + +static const char *operand_txt[] = { + [TCF_EM_OPND_EQ] = "=", + [TCF_EM_OPND_LT] = "<", + [TCF_EM_OPND_GT] = ">", +}; + +static void cmp_dump(struct rtnl_ematch *e, struct nl_dump_params *p) +{ + struct tcf_em_cmp *cmp = rtnl_ematch_data(e); + + if (cmp->flags & TCF_EM_CMP_TRANS) + nl_dump(p, "ntoh%c(", (cmp->align == TCF_EM_ALIGN_U32) ? 'l' : 's'); + + nl_dump(p, "%s at %s+%u", + align_txt[cmp->align], layer_txt[cmp->layer], cmp->off); + + if (cmp->mask) + nl_dump(p, " & 0x%x", cmp->mask); + + if (cmp->flags & TCF_EM_CMP_TRANS) + nl_dump(p, ")"); + + nl_dump(p, " %s %u", operand_txt[cmp->opnd], cmp->val); +} + +static struct rtnl_ematch_ops cmp_ops = { + .eo_kind = TCF_EM_CMP, + .eo_name = "cmp", + .eo_minlen = sizeof(struct tcf_em_cmp), + .eo_datalen = sizeof(struct tcf_em_cmp), + .eo_parse = cmp_parse, + .eo_dump = cmp_dump, +}; + +static void __init cmp_init(void) +{ + rtnl_ematch_register(&cmp_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/cls/ematch/container.c b/libnetwork/libnl3/lib/route/cls/ematch/container.c new file mode 100644 index 0000000..ddbdce0 --- /dev/null +++ b/libnetwork/libnl3/lib/route/cls/ematch/container.c @@ -0,0 +1,41 @@ +/* + * lib/route/cls/ematch/container.c Container Ematch + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2010 Thomas Graf + */ + +#include +#include +#include +#include + +static int container_parse(struct rtnl_ematch *e, void *data, size_t len) +{ + memcpy(e->e_data, data, sizeof(uint32_t)); + + return 0; +} + +static int container_fill(struct rtnl_ematch *e, struct nl_msg *msg) +{ + return nlmsg_append(msg, e->e_data, sizeof(uint32_t), 0); +} + +static struct rtnl_ematch_ops container_ops = { + .eo_kind = TCF_EM_CONTAINER, + .eo_name = "container", + .eo_minlen = sizeof(uint32_t), + .eo_datalen = sizeof(uint32_t), + .eo_parse = container_parse, + .eo_fill = container_fill, +}; + +static void __init container_init(void) +{ + rtnl_ematch_register(&container_ops); +} diff --git a/libnetwork/libnl3/lib/route/cls/ematch/meta.c b/libnetwork/libnl3/lib/route/cls/ematch/meta.c new file mode 100644 index 0000000..11f87d6 --- /dev/null +++ b/libnetwork/libnl3/lib/route/cls/ematch/meta.c @@ -0,0 +1,334 @@ +/* + * lib/route/cls/ematch/meta.c Metadata Match + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf + */ + +/** + * @ingroup ematch + * @defgroup em_meta Metadata Match + * + * @{ + */ + +#include +#include +#include +#include +#include + +struct rtnl_meta_value +{ + uint8_t mv_type; + uint8_t mv_shift; + uint16_t mv_id; + size_t mv_len; +}; + +struct meta_data +{ + struct rtnl_meta_value * left; + struct rtnl_meta_value * right; + uint8_t opnd; +}; + +static struct rtnl_meta_value *meta_alloc(uint8_t type, uint16_t id, + uint8_t shift, void *data, + size_t len) +{ + struct rtnl_meta_value *value; + + if (!(value = calloc(1, sizeof(*value) + len))) + return NULL; + + value->mv_type = type; + value->mv_id = id; + value->mv_shift = shift; + value->mv_len = len; + + memcpy(value + 1, data, len); + + return value; +} + +struct rtnl_meta_value *rtnl_meta_value_alloc_int(uint64_t value) +{ + return meta_alloc(TCF_META_TYPE_INT, TCF_META_ID_VALUE, 0, &value, 8); +} + +struct rtnl_meta_value *rtnl_meta_value_alloc_var(void *data, size_t len) +{ + return meta_alloc(TCF_META_TYPE_VAR, TCF_META_ID_VALUE, 0, data, len); +} + +struct rtnl_meta_value *rtnl_meta_value_alloc_id(uint8_t type, uint16_t id, + uint8_t shift, uint64_t mask) +{ + size_t masklen = 0; + + if (id > TCF_META_ID_MAX) + return NULL; + + if (mask) { + if (type == TCF_META_TYPE_VAR) + return NULL; + + masklen = 8; + } + + return meta_alloc(type, id, shift, &mask, masklen); +} + +void rtnl_meta_value_put(struct rtnl_meta_value *mv) +{ + free(mv); +} + +void rtnl_ematch_meta_set_lvalue(struct rtnl_ematch *e, struct rtnl_meta_value *v) +{ + struct meta_data *m = rtnl_ematch_data(e); + m->left = v; +} + +void rtnl_ematch_meta_set_rvalue(struct rtnl_ematch *e, struct rtnl_meta_value *v) +{ + struct meta_data *m = rtnl_ematch_data(e); + m->right = v; +} + +void rtnl_ematch_meta_set_operand(struct rtnl_ematch *e, uint8_t opnd) +{ + struct meta_data *m = rtnl_ematch_data(e); + m->opnd = opnd; +} + +static struct nla_policy meta_policy[TCA_EM_META_MAX+1] = { + [TCA_EM_META_HDR] = { .minlen = sizeof(struct tcf_meta_hdr) }, + [TCA_EM_META_LVALUE] = { .minlen = 1, }, + [TCA_EM_META_RVALUE] = { .minlen = 1, }, +}; + +static int meta_parse(struct rtnl_ematch *e, void *data, size_t len) +{ + struct meta_data *m = rtnl_ematch_data(e); + struct nlattr *tb[TCA_EM_META_MAX+1]; + struct rtnl_meta_value *v; + struct tcf_meta_hdr *hdr; + void *vdata = NULL; + size_t vlen = 0; + int err; + + if ((err = nla_parse(tb, TCA_EM_META_MAX, data, len, meta_policy)) < 0) + return err; + + if (!tb[TCA_EM_META_HDR]) + return -NLE_MISSING_ATTR; + + hdr = nla_data(tb[TCA_EM_META_HDR]); + + if (tb[TCA_EM_META_LVALUE]) { + vdata = nla_data(tb[TCA_EM_META_LVALUE]); + vlen = nla_len(tb[TCA_EM_META_LVALUE]); + } + + v = meta_alloc(TCF_META_TYPE(hdr->left.kind), + TCF_META_ID(hdr->left.kind), + hdr->left.shift, vdata, vlen); + if (!v) + return -NLE_NOMEM; + + m->left = v; + + vlen = 0; + if (tb[TCA_EM_META_RVALUE]) { + vdata = nla_data(tb[TCA_EM_META_RVALUE]); + vlen = nla_len(tb[TCA_EM_META_RVALUE]); + } + + v = meta_alloc(TCF_META_TYPE(hdr->right.kind), + TCF_META_ID(hdr->right.kind), + hdr->right.shift, vdata, vlen); + if (!v) { + rtnl_meta_value_put(m->left); + return -NLE_NOMEM; + } + + m->right = v; + m->opnd = hdr->left.op; + + return 0; +} + +static const struct trans_tbl meta_int[] = { + __ADD(TCF_META_ID_RANDOM, random) + __ADD(TCF_META_ID_LOADAVG_0, loadavg_0) + __ADD(TCF_META_ID_LOADAVG_1, loadavg_1) + __ADD(TCF_META_ID_LOADAVG_2, loadavg_2) + __ADD(TCF_META_ID_DEV, dev) + __ADD(TCF_META_ID_PRIORITY, prio) + __ADD(TCF_META_ID_PROTOCOL, proto) + __ADD(TCF_META_ID_PKTTYPE, pkttype) + __ADD(TCF_META_ID_PKTLEN, pktlen) + __ADD(TCF_META_ID_DATALEN, datalen) + __ADD(TCF_META_ID_MACLEN, maclen) + __ADD(TCF_META_ID_NFMARK, mark) + __ADD(TCF_META_ID_TCINDEX, tcindex) + __ADD(TCF_META_ID_RTCLASSID, rtclassid) + __ADD(TCF_META_ID_RTIIF, rtiif) + __ADD(TCF_META_ID_SK_FAMILY, sk_family) + __ADD(TCF_META_ID_SK_STATE, sk_state) + __ADD(TCF_META_ID_SK_REUSE, sk_reuse) + __ADD(TCF_META_ID_SK_REFCNT, sk_refcnt) + __ADD(TCF_META_ID_SK_RCVBUF, sk_rcvbuf) + __ADD(TCF_META_ID_SK_SNDBUF, sk_sndbuf) + __ADD(TCF_META_ID_SK_SHUTDOWN, sk_sutdown) + __ADD(TCF_META_ID_SK_PROTO, sk_proto) + __ADD(TCF_META_ID_SK_TYPE, sk_type) + __ADD(TCF_META_ID_SK_RMEM_ALLOC, sk_rmem_alloc) + __ADD(TCF_META_ID_SK_WMEM_ALLOC, sk_wmem_alloc) + __ADD(TCF_META_ID_SK_WMEM_QUEUED, sk_wmem_queued) + __ADD(TCF_META_ID_SK_RCV_QLEN, sk_rcv_qlen) + __ADD(TCF_META_ID_SK_SND_QLEN, sk_snd_qlen) + __ADD(TCF_META_ID_SK_ERR_QLEN, sk_err_qlen) + __ADD(TCF_META_ID_SK_FORWARD_ALLOCS, sk_forward_allocs) + __ADD(TCF_META_ID_SK_ALLOCS, sk_allocs) + __ADD(TCF_META_ID_SK_ROUTE_CAPS, sk_route_caps) + __ADD(TCF_META_ID_SK_HASH, sk_hash) + __ADD(TCF_META_ID_SK_LINGERTIME, sk_lingertime) + __ADD(TCF_META_ID_SK_ACK_BACKLOG, sk_ack_backlog) + __ADD(TCF_META_ID_SK_MAX_ACK_BACKLOG, sk_max_ack_backlog) + __ADD(TCF_META_ID_SK_PRIO, sk_prio) + __ADD(TCF_META_ID_SK_RCVLOWAT, sk_rcvlowat) + __ADD(TCF_META_ID_SK_RCVTIMEO, sk_rcvtimeo) + __ADD(TCF_META_ID_SK_SNDTIMEO, sk_sndtimeo) + __ADD(TCF_META_ID_SK_SENDMSG_OFF, sk_sendmsg_off) + __ADD(TCF_META_ID_SK_WRITE_PENDING, sk_write_pending) + __ADD(TCF_META_ID_VLAN_TAG, vlan) + __ADD(TCF_META_ID_RXHASH, rxhash) +}; + +static char *int_id2str(int id, char *buf, size_t size) +{ + return __type2str(id, buf, size, meta_int, ARRAY_SIZE(meta_int)); +} + +static const struct trans_tbl meta_var[] = { + __ADD(TCF_META_ID_DEV,devname) + __ADD(TCF_META_ID_SK_BOUND_IF,sk_bound_if) +}; + +static char *var_id2str(int id, char *buf, size_t size) +{ + return __type2str(id, buf, size, meta_var, ARRAY_SIZE(meta_var)); +} + +static void dump_value(struct rtnl_meta_value *v, struct nl_dump_params *p) +{ + char buf[32]; + + switch (v->mv_type) { + case TCF_META_TYPE_INT: + if (v->mv_id == TCF_META_ID_VALUE) { + nl_dump(p, "%u", + *(uint32_t *) (v + 1)); + } else { + nl_dump(p, "%s", + int_id2str(v->mv_id, buf, sizeof(buf))); + + if (v->mv_shift) + nl_dump(p, " >> %u", v->mv_shift); + + if (v->mv_len == 4) + nl_dump(p, " & %#x", *(uint32_t *) (v + 1)); + else if (v->mv_len == 8) + nl_dump(p, " & %#x", *(uint64_t *) (v + 1)); + } + break; + + case TCF_META_TYPE_VAR: + if (v->mv_id == TCF_META_ID_VALUE) { + nl_dump(p, "%s", (char *) (v + 1)); + } else { + nl_dump(p, "%s", + var_id2str(v->mv_id, buf, sizeof(buf))); + + if (v->mv_shift) + nl_dump(p, " >> %u", v->mv_shift); + } + break; + } +} + +static void meta_dump(struct rtnl_ematch *e, struct nl_dump_params *p) +{ + struct meta_data *m = rtnl_ematch_data(e); + char buf[32]; + + nl_dump(p, "meta("); + dump_value(m->left, p); + + nl_dump(p, " %s ", rtnl_ematch_opnd2txt(m->opnd, buf, sizeof(buf))); + + dump_value(m->right, p); + nl_dump(p, ")"); +} + +static int meta_fill(struct rtnl_ematch *e, struct nl_msg *msg) +{ + struct meta_data *m = rtnl_ematch_data(e); + struct tcf_meta_hdr hdr; + + if (!(m->left && m->right)) + return -NLE_MISSING_ATTR; + + memset(&hdr, 0, sizeof(hdr)); + hdr.left.kind = (m->left->mv_type << 12) & TCF_META_TYPE_MASK; + hdr.left.kind |= m->left->mv_id & TCF_META_ID_MASK; + hdr.left.shift = m->left->mv_shift; + hdr.left.op = m->opnd; + hdr.right.kind = (m->right->mv_type << 12) & TCF_META_TYPE_MASK; + hdr.right.kind |= m->right->mv_id & TCF_META_ID_MASK; + + NLA_PUT(msg, TCA_EM_META_HDR, sizeof(hdr), &hdr); + + if (m->left->mv_len) + NLA_PUT(msg, TCA_EM_META_LVALUE, m->left->mv_len, (m->left + 1)); + + if (m->right->mv_len) + NLA_PUT(msg, TCA_EM_META_RVALUE, m->right->mv_len, (m->right + 1)); + + return 0; + +nla_put_failure: + return -NLE_NOMEM; +} + +static void meta_free(struct rtnl_ematch *e) +{ + struct meta_data *m = rtnl_ematch_data(e); + free(m->left); + free(m->right); +} + +static struct rtnl_ematch_ops meta_ops = { + .eo_kind = TCF_EM_META, + .eo_name = "meta", + .eo_minlen = sizeof(struct tcf_meta_hdr), + .eo_datalen = sizeof(struct meta_data), + .eo_parse = meta_parse, + .eo_dump = meta_dump, + .eo_fill = meta_fill, + .eo_free = meta_free, +}; + +static void __init meta_init(void) +{ + rtnl_ematch_register(&meta_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/cls/ematch/nbyte.c b/libnetwork/libnl3/lib/route/cls/ematch/nbyte.c new file mode 100644 index 0000000..25a9866 --- /dev/null +++ b/libnetwork/libnl3/lib/route/cls/ematch/nbyte.c @@ -0,0 +1,139 @@ +/* + * lib/route/cls/ematch/nbyte.c Nbyte comparison + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf + */ + +/** + * @ingroup ematch + * @defgroup em_nbyte N-Byte Comparison + * + * @{ + */ + +#include +#include +#include +#include +#include + +struct nbyte_data +{ + struct tcf_em_nbyte cfg; + uint8_t * pattern; +}; + +void rtnl_ematch_nbyte_set_offset(struct rtnl_ematch *e, uint8_t layer, + uint16_t offset) +{ + struct nbyte_data *n = rtnl_ematch_data(e); + n->cfg.off = offset; + n->cfg.layer = layer; +} + +uint16_t rtnl_ematch_nbyte_get_offset(struct rtnl_ematch *e) +{ + return ((struct nbyte_data *) rtnl_ematch_data(e))->cfg.off; +} + +uint8_t rtnl_ematch_nbyte_get_layer(struct rtnl_ematch *e) +{ + return ((struct nbyte_data *) rtnl_ematch_data(e))->cfg.layer; +} + +void rtnl_ematch_nbyte_set_pattern(struct rtnl_ematch *e, + uint8_t *pattern, size_t len) +{ + struct nbyte_data *n = rtnl_ematch_data(e); + + if (n->pattern) + free(n->pattern); + + n->pattern = pattern; + n->cfg.len = len; +} + +uint8_t *rtnl_ematch_nbyte_get_pattern(struct rtnl_ematch *e) +{ + return ((struct nbyte_data *) rtnl_ematch_data(e))->pattern; +} + +size_t rtnl_ematch_nbyte_get_len(struct rtnl_ematch *e) +{ + return ((struct nbyte_data *) rtnl_ematch_data(e))->cfg.len; +} + +static const char *layer_txt(struct tcf_em_nbyte *nbyte) +{ + switch (nbyte->layer) { + case TCF_LAYER_LINK: + return "link"; + case TCF_LAYER_NETWORK: + return "net"; + case TCF_LAYER_TRANSPORT: + return "trans"; + default: + return "?"; + } +} + +static int nbyte_parse(struct rtnl_ematch *e, void *data, size_t len) +{ + struct nbyte_data *n = rtnl_ematch_data(e); + size_t hdrlen = sizeof(struct tcf_em_nbyte); + size_t plen = len - hdrlen; + + memcpy(&n->cfg, data, hdrlen); + if (plen > 0) { + if (!(n->pattern = calloc(1, plen))) + return -NLE_NOMEM; + + memcpy(n->pattern, data + hdrlen, plen); + } + + return 0; +} + +static void nbyte_dump(struct rtnl_ematch *e, struct nl_dump_params *p) +{ + struct nbyte_data *n = rtnl_ematch_data(e); + int i; + + nl_dump(p, "pattern(%u:[", n->cfg.len); + + for (i = 0; i < n->cfg.len; i++) { + nl_dump(p, "%02x", n->pattern[i]); + if (i+1 < n->cfg.len) + nl_dump(p, " "); + } + + nl_dump(p, "] at %s+%u)", layer_txt(&n->cfg), n->cfg.off); +} + +static void nbyte_free(struct rtnl_ematch *e) +{ + struct nbyte_data *n = rtnl_ematch_data(e); + free(n->pattern); +} + +static struct rtnl_ematch_ops nbyte_ops = { + .eo_kind = TCF_EM_NBYTE, + .eo_name = "nbyte", + .eo_minlen = sizeof(struct tcf_em_nbyte), + .eo_datalen = sizeof(struct nbyte_data), + .eo_parse = nbyte_parse, + .eo_dump = nbyte_dump, + .eo_free = nbyte_free, +}; + +static void __init nbyte_init(void) +{ + rtnl_ematch_register(&nbyte_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/cls/ematch/text.c b/libnetwork/libnl3/lib/route/cls/ematch/text.c new file mode 100644 index 0000000..9d0241e --- /dev/null +++ b/libnetwork/libnl3/lib/route/cls/ematch/text.c @@ -0,0 +1,183 @@ +/* + * lib/route/cls/ematch/text.c Text Search + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf + */ + +/** + * @ingroup ematch + * @defgroup em_text Text Search + * + * @{ + */ + +#include +#include +#include +#include +#include + +struct text_data +{ + struct tcf_em_text cfg; + char * pattern; +}; + +void rtnl_ematch_text_set_from(struct rtnl_ematch *e, uint8_t layer, + uint16_t offset) +{ + struct text_data *t = rtnl_ematch_data(e); + t->cfg.from_offset = offset; + t->cfg.from_layer = layer; +} + +uint16_t rtnl_ematch_text_get_from_offset(struct rtnl_ematch *e) +{ + return ((struct text_data *) rtnl_ematch_data(e))->cfg.from_offset; +} + +uint8_t rtnl_ematch_text_get_from_layer(struct rtnl_ematch *e) +{ + return ((struct text_data *) rtnl_ematch_data(e))->cfg.from_layer; +} + +void rtnl_ematch_text_set_to(struct rtnl_ematch *e, uint8_t layer, + uint16_t offset) +{ + struct text_data *t = rtnl_ematch_data(e); + t->cfg.to_offset = offset; + t->cfg.to_layer = layer; +} + +uint16_t rtnl_ematch_text_get_to_offset(struct rtnl_ematch *e) +{ + return ((struct text_data *) rtnl_ematch_data(e))->cfg.to_offset; +} + +uint8_t rtnl_ematch_text_get_to_layer(struct rtnl_ematch *e) +{ + return ((struct text_data *) rtnl_ematch_data(e))->cfg.to_layer; +} + +void rtnl_ematch_text_set_pattern(struct rtnl_ematch *e, + char *pattern, size_t len) +{ + struct text_data *t = rtnl_ematch_data(e); + + if (t->pattern) + free(t->pattern); + + t->pattern = pattern; + t->cfg.pattern_len = len; +} + +char *rtnl_ematch_text_get_pattern(struct rtnl_ematch *e) +{ + return ((struct text_data *) rtnl_ematch_data(e))->pattern; +} + +size_t rtnl_ematch_text_get_len(struct rtnl_ematch *e) +{ + return ((struct text_data *) rtnl_ematch_data(e))->cfg.pattern_len; +} + +void rtnl_ematch_text_set_algo(struct rtnl_ematch *e, const char *algo) +{ + struct text_data *t = rtnl_ematch_data(e); + + strncpy(t->cfg.algo, algo, sizeof(t->cfg.algo)); +} + +char *rtnl_ematch_text_get_algo(struct rtnl_ematch *e) +{ + struct text_data *t = rtnl_ematch_data(e); + + return t->cfg.algo[0] ? t->cfg.algo : NULL; +} + +static int text_parse(struct rtnl_ematch *e, void *data, size_t len) +{ + struct text_data *t = rtnl_ematch_data(e); + size_t hdrlen = sizeof(struct tcf_em_text); + size_t plen = len - hdrlen; + + memcpy(&t->cfg, data, hdrlen); + + if (t->cfg.pattern_len > plen) + return -NLE_INVAL; + + if (t->cfg.pattern_len > 0) { + if (!(t->pattern = calloc(1, t->cfg.pattern_len))) + return -NLE_NOMEM; + + memcpy(t->pattern, data + hdrlen, t->cfg.pattern_len); + } + + return 0; +} + +static void text_dump(struct rtnl_ematch *e, struct nl_dump_params *p) +{ + struct text_data *t = rtnl_ematch_data(e); + char buf[64]; + + nl_dump(p, "text(%s \"%s\"", + t->cfg.algo[0] ? t->cfg.algo : "no-algo", + t->pattern ? : "no-pattern"); + + if (t->cfg.from_layer || t->cfg.from_offset) { + nl_dump(p, " from %s", + rtnl_ematch_offset2txt(t->cfg.from_layer, + t->cfg.from_offset, + buf, sizeof(buf))); + } + + if (t->cfg.to_layer || t->cfg.to_offset) { + nl_dump(p, " to %s", + rtnl_ematch_offset2txt(t->cfg.to_layer, + t->cfg.to_offset, + buf, sizeof(buf))); + } + + nl_dump(p, ")"); +} + +static int text_fill(struct rtnl_ematch *e, struct nl_msg *msg) +{ + struct text_data *t = rtnl_ematch_data(e); + int err; + + if ((err = nlmsg_append(msg, &t->cfg, sizeof(t->cfg), 0)) < 0) + return err; + + return nlmsg_append(msg, t->pattern, t->cfg.pattern_len, 0); +} + +static void text_free(struct rtnl_ematch *e) +{ + struct text_data *t = rtnl_ematch_data(e); + free(t->pattern); +} + +static struct rtnl_ematch_ops text_ops = { + .eo_kind = TCF_EM_TEXT, + .eo_name = "text", + .eo_minlen = sizeof(struct tcf_em_text), + .eo_datalen = sizeof(struct text_data), + .eo_parse = text_parse, + .eo_dump = text_dump, + .eo_fill = text_fill, + .eo_free = text_free, +}; + +static void __init text_init(void) +{ + rtnl_ematch_register(&text_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/cls/ematch_grammar.l b/libnetwork/libnl3/lib/route/cls/ematch_grammar.l new file mode 100644 index 0000000..07e7e8c --- /dev/null +++ b/libnetwork/libnl3/lib/route/cls/ematch_grammar.l @@ -0,0 +1,162 @@ +/* + * lib/route/cls/ematch_grammar.l ematch expression grammar + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf + */ + +%{ + #include + #include + #include + #include + #include + #include "ematch_syntax.h" +%} + +%option 8bit +%option reentrant +%option warn +%option noyywrap +%option noinput +%option nounput +%option bison-bridge +%option prefix="ematch_" + +%x QUOTE + +%% + +[ \t\r\n]+ + +\" { + NL_DBG(4, "Beginning of quote\n"); + yylval->q.len = 32; + if (!(yylval->q.data = calloc(1, yylval->q.len))) + return ERROR; + + yylval->q.index = 0; + BEGIN(QUOTE); + } + +[^\\\n\"]+ { + memcpy(yylval->q.data + yylval->q.index, yytext, + strlen(yytext)); + yylval->q.index += strlen(yytext); + } + +\" { + BEGIN(0); + return QUOTED; + } + + +[[:digit:]]+ | +0[xX][[:xdigit:]]+ { + yylval->i = strtoul(yytext, NULL, 0); + return NUMBER; + } + +eq | +"=" return KW_EQ; +gt | +">" return KW_GT; +lt | +"<" return KW_LT; + +[aA][nN][dD] | +"&&" { yylval->i = TCF_EM_REL_AND; return LOGIC; } +[oO][rR] | +"||" { yylval->i = TCF_EM_REL_OR; return LOGIC; } +[nN][oO][tT] | +"!" return NOT; + +[cC][mM][pP] { yylval->i = TCF_EM_CMP; return EMATCH_CMP; } +[pP][aA][tT][tT][eE][rR][nN] { yylval->i = TCF_EM_NBYTE; return EMATCH_NBYTE; } +[tT][eE][xX][tT] { yylval->i = TCF_EM_TEXT; return EMATCH_TEXT; } +[mM][eE][tT][aA] { yylval->i = TCF_EM_META; return EMATCH_META; } + +"(" return KW_OPEN; +")" return KW_CLOSE; +[mM][aA][sS][kK] | +"&" return KW_MASK; +[sS][hH][iI][fF][tT] | +">>" return KW_SHIFT; +[aA][tT] return KW_AT; +"+" return KW_PLUS; +[fF][rR][oO][mM] return KW_FROM; +[tT][oO] return KW_TO; + +[uU]8 { yylval->i = TCF_EM_ALIGN_U8; return ALIGN; } +[uU]16 { yylval->i = TCF_EM_ALIGN_U16; return ALIGN; } +[uU]32 { yylval->i = TCF_EM_ALIGN_U32; return ALIGN; } + +[lL][iI][nN][kK] | +[eE][tT][hH] { yylval->i = TCF_LAYER_LINK; return LAYER; } +[nN][eE][tT] | +[iI][pP]6 | +[iI][pP] { yylval->i = TCF_LAYER_NETWORK; return LAYER; } +[tT][rR][aA][nN][sS][pP][oO][rR][tT] | +[tT][cC][pP] { yylval->i = TCF_LAYER_TRANSPORT; return LAYER; } + +random return META_RANDOM; +loadavg_0 return META_LOADAVG_0; +loadavg_1 return META_LOADAVG_1; +loadavg_2 return META_LOADAVG_2; +dev return META_DEV; +prio return META_PRIO; +proto return META_PROTO; +pkttype return META_PKTTYPE; +pktlen return META_PKTLEN; +datalen return META_DATALEN; +maclen return META_MACLEN; +mark return META_MARK; +tcindex return META_TCINDEX; +rtclassid return META_RTCLASSID; +rtiif return META_RTIIF; +sk_family return META_SK_FAMILY; +sk_state return META_SK_STATE; +sk_reuse return META_SK_REUSE; +sk_refcnt return META_SK_REFCNT; +sk_rcvbuf return META_SK_RCVBUF; +sk_sndbuf return META_SK_SNDBUF; +sk_shutdown return META_SK_SHUTDOWN; +sk_proto return META_SK_PROTO; +sk_type return META_SK_TYPE; +sk_rmem_alloc return META_SK_RMEM_ALLOC; +sk_wmem_alloc return META_SK_WMEM_ALLOC; +sk_wmem_queued return META_SK_WMEM_QUEUED; +sk_rcv_qlen return META_SK_RCV_QLEN; +sk_snd_qlen return META_SK_SND_QLEN; +sk_err_qlen return META_SK_ERR_QLEN; +sk_forward_allocs return META_SK_FORWARD_ALLOCS; +sk_allocs return META_SK_ALLOCS; +sk_route_caps return META_SK_ROUTE_CAPS; +sk_hash return META_SK_HASH; +sk_lingertime return META_SK_LINGERTIME; +sk_ack_backlog return META_SK_ACK_BACKLOG; +sk_max_ack_backlog return META_SK_MAX_ACK_BACKLOG; +sk_prio return META_SK_PRIO; +sk_rcvlowat return META_SK_RCVLOWAT; +sk_rcvtimeo return META_SK_RCVTIMEO; +sk_sndtimeo return META_SK_SNDTIMEO; +sk_sendmsg_off return META_SK_SENDMSG_OFF; +sk_write_pending return META_SK_WRITE_PENDING; +vlan return META_VLAN; +rxhash return META_RXHASH; + +devname return META_DEVNAME; +sk_bound_if return META_SK_BOUND_IF; + + +[^ \t\r\n+()=<>&|\"]+ { + yylval->s = strdup(yytext); + if (yylval->s == NULL) + return ERROR; + NL_DBG(4, "lex STR=%s\n", yylval->s); + return STR; + } diff --git a/libnetwork/libnl3/lib/route/cls/ematch_syntax.y b/libnetwork/libnl3/lib/route/cls/ematch_syntax.y new file mode 100644 index 0000000..61c91d1 --- /dev/null +++ b/libnetwork/libnl3/lib/route/cls/ematch_syntax.y @@ -0,0 +1,497 @@ +/* + * lib/route/cls/ematch_syntax.y ematch expression syntax + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf + */ + +%{ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define META_ALLOC rtnl_meta_value_alloc_id +#define META_ID(name) TCF_META_ID_##name +#define META_INT TCF_META_TYPE_INT +#define META_VAR TCF_META_TYPE_VAR +%} + +%error-verbose +%define api.pure +%name-prefix "ematch_" + +%parse-param {void *scanner} +%parse-param {char **errp} +%parse-param {struct nl_list_head *root} +%lex-param {void *scanner} + +%union { + struct tcf_em_cmp cmp; + struct ematch_quoted q; + struct rtnl_ematch * e; + struct rtnl_pktloc * loc; + struct rtnl_meta_value *mv; + uint32_t i; + uint64_t i64; + char * s; +} + +%{ +extern int ematch_lex(YYSTYPE *, void *); + +static void yyerror(void *scanner, char **errp, struct nl_list_head *root, const char *msg) +{ + if (msg) + asprintf(errp, "%s", msg); +} +%} + +%token ERROR LOGIC NOT OPERAND NUMBER ALIGN LAYER +%token KW_OPEN "(" +%token KW_CLOSE ")" +%token KW_PLUS "+" +%token KW_MASK "mask" +%token KW_SHIFT ">>" +%token KW_AT "at" +%token EMATCH_CMP "cmp" +%token EMATCH_NBYTE "pattern" +%token EMATCH_TEXT "text" +%token EMATCH_META "meta" +%token KW_EQ "=" +%token KW_GT ">" +%token KW_LT "<" +%token KW_FROM "from" +%token KW_TO "to" + +%token META_RANDOM "random" +%token META_LOADAVG_0 "loadavg_0" +%token META_LOADAVG_1 "loadavg_1" +%token META_LOADAVG_2 "loadavg_2" +%token META_DEV "dev" +%token META_PRIO "prio" +%token META_PROTO "proto" +%token META_PKTTYPE "pkttype" +%token META_PKTLEN "pktlen" +%token META_DATALEN "datalen" +%token META_MACLEN "maclen" +%token META_MARK "mark" +%token META_TCINDEX "tcindex" +%token META_RTCLASSID "rtclassid" +%token META_RTIIF "rtiif" +%token META_SK_FAMILY "sk_family" +%token META_SK_STATE "sk_state" +%token META_SK_REUSE "sk_reuse" +%token META_SK_REFCNT "sk_refcnt" +%token META_SK_RCVBUF "sk_rcvbuf" +%token META_SK_SNDBUF "sk_sndbuf" +%token META_SK_SHUTDOWN "sk_shutdown" +%token META_SK_PROTO "sk_proto" +%token META_SK_TYPE "sk_type" +%token META_SK_RMEM_ALLOC "sk_rmem_alloc" +%token META_SK_WMEM_ALLOC "sk_wmem_alloc" +%token META_SK_WMEM_QUEUED "sk_wmem_queued" +%token META_SK_RCV_QLEN "sk_rcv_qlen" +%token META_SK_SND_QLEN "sk_snd_qlen" +%token META_SK_ERR_QLEN "sk_err_qlen" +%token META_SK_FORWARD_ALLOCS "sk_forward_allocs" +%token META_SK_ALLOCS "sk_allocs" +%token META_SK_ROUTE_CAPS "sk_route_caps" +%token META_SK_HASH "sk_hash" +%token META_SK_LINGERTIME "sk_lingertime" +%token META_SK_ACK_BACKLOG "sk_ack_backlog" +%token META_SK_MAX_ACK_BACKLOG "sk_max_ack_backlog" +%token META_SK_PRIO "sk_prio" +%token META_SK_RCVLOWAT "sk_rcvlowat" +%token META_SK_RCVTIMEO "sk_rcvtimeo" +%token META_SK_SNDTIMEO "sk_sndtimeo" +%token META_SK_SENDMSG_OFF "sk_sendmsg_off" +%token META_SK_WRITE_PENDING "sk_write_pending" +%token META_VLAN "vlan" +%token META_RXHASH "rxhash" +%token META_DEVNAME "devname" +%token META_SK_BOUND_IF "sk_bound_if" + +%token STR + +%token QUOTED + +%type align operand shift meta_int_id meta_var_id +%type mask +%type expr match ematch +%type cmp_expr cmp_match +%type pktloc text_from text_to +%type pattern +%type meta_value + +%destructor { free($$); NL_DBG(2, "string destructor\n"); } +%destructor { rtnl_pktloc_put($$); NL_DBG(2, "pktloc destructor\n"); } +%destructor { free($$.data); NL_DBG(2, "quoted destructor\n"); } +%destructor { rtnl_meta_value_put($$); NL_DBG(2, "meta value destructor\n"); } + +%start input + +%% + +input: + /* empty */ + | expr + { + nl_list_add_tail(root, &$1->e_list); + } + ; + +expr: + match + { + $$ = $1; + } + | match LOGIC expr + { + rtnl_ematch_set_flags($1, $2); + + /* make ematch new head */ + nl_list_add_tail(&$1->e_list, &$3->e_list); + + $$ = $1; + } + ; + +match: + NOT ematch + { + rtnl_ematch_set_flags($2, TCF_EM_INVERT); + $$ = $2; + } + | ematch + { + $$ = $1; + } + ; + +ematch: + /* CMP */ + cmp_match + { + struct rtnl_ematch *e; + + if (!(e = rtnl_ematch_alloc())) { + asprintf(errp, "Unable to allocate ematch object"); + YYABORT; + } + + if (rtnl_ematch_set_kind(e, TCF_EM_CMP) < 0) + BUG(); + + rtnl_ematch_cmp_set(e, &$1); + $$ = e; + } + | EMATCH_NBYTE "(" pktloc KW_EQ pattern ")" + { + struct rtnl_ematch *e; + + if (!(e = rtnl_ematch_alloc())) { + asprintf(errp, "Unable to allocate ematch object"); + YYABORT; + } + + if (rtnl_ematch_set_kind(e, TCF_EM_NBYTE) < 0) + BUG(); + + rtnl_ematch_nbyte_set_offset(e, $3->layer, $3->offset); + rtnl_pktloc_put($3); + rtnl_ematch_nbyte_set_pattern(e, (uint8_t *) $5.data, $5.index); + + $$ = e; + } + | EMATCH_TEXT "(" STR QUOTED text_from text_to ")" + { + struct rtnl_ematch *e; + + if (!(e = rtnl_ematch_alloc())) { + asprintf(errp, "Unable to allocate ematch object"); + YYABORT; + } + + if (rtnl_ematch_set_kind(e, TCF_EM_TEXT) < 0) + BUG(); + + rtnl_ematch_text_set_algo(e, $3); + rtnl_ematch_text_set_pattern(e, $4.data, $4.index); + + if ($5) { + rtnl_ematch_text_set_from(e, $5->layer, $5->offset); + rtnl_pktloc_put($5); + } + + if ($6) { + rtnl_ematch_text_set_to(e, $6->layer, $6->offset); + rtnl_pktloc_put($6); + } + + $$ = e; + } + | EMATCH_META "(" meta_value operand meta_value ")" + { + struct rtnl_ematch *e; + + if (!(e = rtnl_ematch_alloc())) { + asprintf(errp, "Unable to allocate ematch object"); + YYABORT; + } + + if (rtnl_ematch_set_kind(e, TCF_EM_META) < 0) + BUG(); + + rtnl_ematch_meta_set_lvalue(e, $3); + rtnl_ematch_meta_set_rvalue(e, $5); + rtnl_ematch_meta_set_operand(e, $4); + + $$ = e; + } + /* CONTAINER */ + | "(" expr ")" + { + struct rtnl_ematch *e; + + if (!(e = rtnl_ematch_alloc())) { + asprintf(errp, "Unable to allocate ematch object"); + YYABORT; + } + + if (rtnl_ematch_set_kind(e, TCF_EM_CONTAINER) < 0) + BUG(); + + /* Make e->childs the list head of a the ematch sequence */ + nl_list_add_tail(&e->e_childs, &$2->e_list); + + $$ = e; + } + ; + +/* + * CMP match + * + * match := cmp(expr) | expr + * expr := pktloc (=|>|<) NUMBER + * pktloc := alias | definition + * + */ +cmp_match: + EMATCH_CMP "(" cmp_expr ")" + { $$ = $3; } + | cmp_expr + { $$ = $1; } + ; + +cmp_expr: + pktloc operand NUMBER + { + if ($1->align == TCF_EM_ALIGN_U16 || + $1->align == TCF_EM_ALIGN_U32) + $$.flags = TCF_EM_CMP_TRANS; + + memset(&$$, 0, sizeof($$)); + + $$.mask = $1->mask; + $$.off = $1->offset; + $$.align = $1->align; + $$.layer = $1->layer; + $$.opnd = $2; + $$.val = $3; + + rtnl_pktloc_put($1); + } + ; + +text_from: + /* empty */ + { $$ = NULL; } + | "from" pktloc + { $$ = $2; } + ; + +text_to: + /* empty */ + { $$ = NULL; } + | "to" pktloc + { $$ = $2; } + ; + +meta_value: + QUOTED + { $$ = rtnl_meta_value_alloc_var($1.data, $1.len); } + | NUMBER + { $$ = rtnl_meta_value_alloc_int($1); } + | meta_int_id shift mask + { $$ = META_ALLOC(META_INT, $1, $2, $3); } + | meta_var_id shift + { $$ = META_ALLOC(META_VAR, $1, $2, 0); } + ; + +meta_int_id: + META_RANDOM { $$ = META_ID(RANDOM); } + |META_LOADAVG_0 { $$ = META_ID(LOADAVG_0); } + |META_LOADAVG_1 { $$ = META_ID(LOADAVG_1); } + |META_LOADAVG_2 { $$ = META_ID(LOADAVG_2); } + | META_DEV { $$ = META_ID(DEV); } + | META_PRIO { $$ = META_ID(PRIORITY); } + | META_PROTO { $$ = META_ID(PROTOCOL); } + | META_PKTTYPE { $$ = META_ID(PKTTYPE); } + | META_PKTLEN { $$ = META_ID(PKTLEN); } + | META_DATALEN { $$ = META_ID(DATALEN); } + | META_MACLEN { $$ = META_ID(MACLEN); } + | META_MARK { $$ = META_ID(NFMARK); } + | META_TCINDEX { $$ = META_ID(TCINDEX); } + | META_RTCLASSID { $$ = META_ID(RTCLASSID); } + | META_RTIIF { $$ = META_ID(RTIIF); } + | META_SK_FAMILY { $$ = META_ID(SK_FAMILY); } + | META_SK_STATE { $$ = META_ID(SK_STATE); } + | META_SK_REUSE { $$ = META_ID(SK_REUSE); } + | META_SK_REFCNT { $$ = META_ID(SK_REFCNT); } + | META_SK_RCVBUF { $$ = META_ID(SK_RCVBUF); } + | META_SK_SNDBUF { $$ = META_ID(SK_SNDBUF); } + | META_SK_SHUTDOWN { $$ = META_ID(SK_SHUTDOWN); } + | META_SK_PROTO { $$ = META_ID(SK_PROTO); } + | META_SK_TYPE { $$ = META_ID(SK_TYPE); } + | META_SK_RMEM_ALLOC { $$ = META_ID(SK_RMEM_ALLOC); } + | META_SK_WMEM_ALLOC { $$ = META_ID(SK_WMEM_ALLOC); } + | META_SK_WMEM_QUEUED { $$ = META_ID(SK_WMEM_QUEUED); } + | META_SK_RCV_QLEN { $$ = META_ID(SK_RCV_QLEN); } + | META_SK_SND_QLEN { $$ = META_ID(SK_SND_QLEN); } + | META_SK_ERR_QLEN { $$ = META_ID(SK_ERR_QLEN); } + | META_SK_FORWARD_ALLOCS { $$ = META_ID(SK_FORWARD_ALLOCS); } + | META_SK_ALLOCS { $$ = META_ID(SK_ALLOCS); } + | META_SK_ROUTE_CAPS { $$ = META_ID(SK_ROUTE_CAPS); } + | META_SK_HASH { $$ = META_ID(SK_HASH); } + | META_SK_LINGERTIME { $$ = META_ID(SK_LINGERTIME); } + | META_SK_ACK_BACKLOG { $$ = META_ID(SK_ACK_BACKLOG); } + | META_SK_MAX_ACK_BACKLOG { $$ = META_ID(SK_MAX_ACK_BACKLOG); } + | META_SK_PRIO { $$ = META_ID(SK_PRIO); } + | META_SK_RCVLOWAT { $$ = META_ID(SK_RCVLOWAT); } + | META_SK_RCVTIMEO { $$ = META_ID(SK_RCVTIMEO); } + | META_SK_SNDTIMEO { $$ = META_ID(SK_SNDTIMEO); } + | META_SK_SENDMSG_OFF { $$ = META_ID(SK_SENDMSG_OFF); } + | META_SK_WRITE_PENDING { $$ = META_ID(SK_WRITE_PENDING); } + | META_VLAN { $$ = META_ID(VLAN_TAG); } + | META_RXHASH { $$ = META_ID(RXHASH); } + ; + +meta_var_id: + META_DEVNAME { $$ = META_ID(DEV); } + | META_SK_BOUND_IF { $$ = META_ID(SK_BOUND_IF); } + ; + +/* + * pattern + */ +pattern: + QUOTED + { + $$ = $1; + } + | STR + { + struct nl_addr *addr; + + if (nl_addr_parse($1, AF_UNSPEC, &addr) == 0) { + $$.len = nl_addr_get_len(addr); + + $$.index = min_t(int, $$.len, nl_addr_get_prefixlen(addr)/8); + + if (!($$.data = calloc(1, $$.len))) { + nl_addr_put(addr); + YYABORT; + } + + memcpy($$.data, nl_addr_get_binary_addr(addr), $$.len); + nl_addr_put(addr); + } else { + asprintf(errp, "invalid pattern \"%s\"", $1); + YYABORT; + } + } + ; + +/* + * packet location + */ + +pktloc: + STR + { + struct rtnl_pktloc *loc; + + if (rtnl_pktloc_lookup($1, &loc) < 0) { + asprintf(errp, "Packet location \"%s\" not found", $1); + YYABORT; + } + + $$ = loc; + } + /* [u8|u16|u32|NUM at] LAYER + OFFSET [mask MASK] */ + | align LAYER "+" NUMBER mask + { + struct rtnl_pktloc *loc; + + if ($5 && (!$1 || $1 > TCF_EM_ALIGN_U32)) { + asprintf(errp, "mask only allowed for alignments u8|u16|u32"); + YYABORT; + } + + if (!(loc = rtnl_pktloc_alloc())) { + asprintf(errp, "Unable to allocate packet location object"); + YYABORT; + } + + loc->name = strdup(""); + loc->align = $1; + loc->layer = $2; + loc->offset = $4; + loc->mask = $5; + + $$ = loc; + } + ; + +align: + /* empty */ + { $$ = 0; } + | ALIGN "at" + { $$ = $1; } + | NUMBER "at" + { $$ = $1; } + ; + +mask: + /* empty */ + { $$ = 0; } + | KW_MASK NUMBER + { $$ = $2; } + ; + +shift: + /* empty */ + { $$ = 0; } + | KW_SHIFT NUMBER + { $$ = $2; } + ; + +operand: + KW_EQ + { $$ = TCF_EM_OPND_EQ; } + | KW_GT + { $$ = TCF_EM_OPND_GT; } + | KW_LT + { $$ = TCF_EM_OPND_LT; } + ; diff --git a/libnetwork/libnl3/lib/route/cls/fw.c b/libnetwork/libnl3/lib/route/cls/fw.c new file mode 100644 index 0000000..11c9c67 --- /dev/null +++ b/libnetwork/libnl3/lib/route/cls/fw.c @@ -0,0 +1,190 @@ +/* + * lib/route/cls/fw.c fw classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + * Copyright (c) 2006 Petr Gotthard + * Copyright (c) 2006 Siemens AG Oesterreich + */ + +/** + * @ingroup cls + * @defgroup cls_fw Firewall Classifier + * + * @{ + */ + +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define FW_ATTR_CLASSID 0x001 +#define FW_ATTR_ACTION 0x002 +#define FW_ATTR_POLICE 0x004 +#define FW_ATTR_INDEV 0x008 +/** @endcond */ + +static struct nla_policy fw_policy[TCA_FW_MAX+1] = { + [TCA_FW_CLASSID] = { .type = NLA_U32 }, + [TCA_FW_INDEV] = { .type = NLA_STRING, + .maxlen = IFNAMSIZ }, +}; + +static int fw_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct nlattr *tb[TCA_FW_MAX + 1]; + struct rtnl_fw *f = data; + int err; + + err = tca_parse(tb, TCA_FW_MAX, tc, fw_policy); + if (err < 0) + return err; + + if (tb[TCA_FW_CLASSID]) { + f->cf_classid = nla_get_u32(tb[TCA_FW_CLASSID]); + f->cf_mask |= FW_ATTR_CLASSID; + } + + if (tb[TCA_FW_ACT]) { + f->cf_act = nl_data_alloc_attr(tb[TCA_FW_ACT]); + if (!f->cf_act) + return -NLE_NOMEM; + f->cf_mask |= FW_ATTR_ACTION; + } + + if (tb[TCA_FW_POLICE]) { + f->cf_police = nl_data_alloc_attr(tb[TCA_FW_POLICE]); + if (!f->cf_police) + return -NLE_NOMEM; + f->cf_mask |= FW_ATTR_POLICE; + } + + if (tb[TCA_FW_INDEV]) { + nla_strlcpy(f->cf_indev, tb[TCA_FW_INDEV], IFNAMSIZ); + f->cf_mask |= FW_ATTR_INDEV; + } + + return 0; +} + +static void fw_free_data(struct rtnl_tc *tc, void *data) +{ + struct rtnl_fw *f = data; + + nl_data_free(f->cf_act); + nl_data_free(f->cf_police); +} + +static int fw_clone(void *_dst, void *_src) +{ + struct rtnl_fw *dst = _dst, *src = _src; + + if (src->cf_act && !(dst->cf_act = nl_data_clone(src->cf_act))) + return -NLE_NOMEM; + + if (src->cf_police && !(dst->cf_police = nl_data_clone(src->cf_police))) + return -NLE_NOMEM; + + return 0; +} + +static void fw_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_fw *f = data; + + if (f && f->cf_mask & FW_ATTR_CLASSID) { + char buf[32]; + + nl_dump(p, " target %s", + rtnl_tc_handle2str(f->cf_classid, buf, sizeof(buf))); + } +} + +static void fw_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_fw *f = data; + + if (f && f->cf_mask & FW_ATTR_INDEV) + nl_dump(p, "indev %s ", f->cf_indev); +} + +static int fw_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) +{ + struct rtnl_fw *f = data; + + if (!f) + return 0; + + if (f->cf_mask & FW_ATTR_CLASSID) + NLA_PUT_U32(msg, TCA_FW_CLASSID, f->cf_classid); + + if (f->cf_mask & FW_ATTR_ACTION) + NLA_PUT_DATA(msg, TCA_FW_ACT, f->cf_act); + + if (f->cf_mask & FW_ATTR_POLICE) + NLA_PUT_DATA(msg, TCA_FW_POLICE, f->cf_police); + + if (f->cf_mask & FW_ATTR_INDEV) + NLA_PUT_STRING(msg, TCA_FW_INDEV, f->cf_indev); + + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +/** + * @name Attribute Modifications + * @{ + */ + +int rtnl_fw_set_classid(struct rtnl_cls *cls, uint32_t classid) +{ + struct rtnl_fw *f; + + if (!(f = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + + f->cf_classid = classid; + f->cf_mask |= FW_ATTR_CLASSID; + + return 0; +} + +/** @} */ + +static struct rtnl_tc_ops fw_ops = { + .to_kind = "fw", + .to_type = RTNL_TC_TYPE_CLS, + .to_size = sizeof(struct rtnl_fw), + .to_msg_parser = fw_msg_parser, + .to_msg_fill = fw_msg_fill, + .to_free_data = fw_free_data, + .to_clone = fw_clone, + .to_dump = { + [NL_DUMP_LINE] = fw_dump_line, + [NL_DUMP_DETAILS] = fw_dump_details, + }, +}; + +static void __init fw_init(void) +{ + rtnl_tc_register(&fw_ops); +} + +static void __exit fw_exit(void) +{ + rtnl_tc_unregister(&fw_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/cls/police.c b/libnetwork/libnl3/lib/route/cls/police.c new file mode 100644 index 0000000..d7ab26b --- /dev/null +++ b/libnetwork/libnl3/lib/route/cls/police.c @@ -0,0 +1,66 @@ +/* + * lib/route/cls/police.c Policer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#include +#include +#include +#include +#include +#include +#include + +/** + * @name Policer Type + * @{ + */ + +static const struct trans_tbl police_types[] = { + __ADD(TC_POLICE_UNSPEC,unspec) + __ADD(TC_POLICE_OK,ok) + __ADD(TC_POLICE_RECLASSIFY,reclassify) + __ADD(TC_POLICE_SHOT,shot) +#ifdef TC_POLICE_PIPE + __ADD(TC_POLICE_PIPE,pipe) +#endif +}; + +/** + * Transform a policer type number into a character string (Reentrant). + * @arg type policer type + * @arg buf destination buffer + * @arg len buffer length + * + * Transforms a policer type number into a character string and stores + * it in the provided buffer. + * + * @return The destination buffer or the type encoded in hex if no match was found. + */ +char * nl_police2str(int type, char *buf, size_t len) +{ + return __type2str(type, buf, len, police_types, + ARRAY_SIZE(police_types)); +} + +/** + * Transform a character string into a policer type number + * @arg name policer type name + * + * Transform the provided character string specifying a policer + * type into the corresponding numeric value + * + * @return Policer type number or a negative value. + */ +int nl_str2police(const char *name) +{ + return __str2type(name, police_types, ARRAY_SIZE(police_types)); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/cls/u32.c b/libnetwork/libnl3/lib/route/cls/u32.c new file mode 100644 index 0000000..2016460 --- /dev/null +++ b/libnetwork/libnl3/lib/route/cls/u32.c @@ -0,0 +1,551 @@ +/* + * lib/route/cls/u32.c u32 classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + * Copyright (c) 2005-2006 Petr Gotthard + * Copyright (c) 2005-2006 Siemens AG Oesterreich + */ + +/** + * @ingroup cls + * @defgroup cls_u32 Universal 32-bit Classifier + * + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define U32_ATTR_DIVISOR 0x001 +#define U32_ATTR_HASH 0x002 +#define U32_ATTR_CLASSID 0x004 +#define U32_ATTR_LINK 0x008 +#define U32_ATTR_PCNT 0x010 +#define U32_ATTR_SELECTOR 0x020 +#define U32_ATTR_ACTION 0x040 +#define U32_ATTR_POLICE 0x080 +#define U32_ATTR_INDEV 0x100 +/** @endcond */ + +static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u) +{ + return (struct tc_u32_sel *) u->cu_selector->d_data; +} + +static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u) +{ + if (!u->cu_selector) + u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel)); + + return u32_selector(u); +} + +static struct nla_policy u32_policy[TCA_U32_MAX+1] = { + [TCA_U32_DIVISOR] = { .type = NLA_U32 }, + [TCA_U32_HASH] = { .type = NLA_U32 }, + [TCA_U32_CLASSID] = { .type = NLA_U32 }, + [TCA_U32_LINK] = { .type = NLA_U32 }, + [TCA_U32_INDEV] = { .type = NLA_STRING, + .maxlen = IFNAMSIZ }, + [TCA_U32_SEL] = { .minlen = sizeof(struct tc_u32_sel) }, + [TCA_U32_PCNT] = { .minlen = sizeof(struct tc_u32_pcnt) }, +}; + +static int u32_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct rtnl_u32 *u = data; + struct nlattr *tb[TCA_U32_MAX + 1]; + int err; + + err = tca_parse(tb, TCA_U32_MAX, tc, u32_policy); + if (err < 0) + return err; + + if (tb[TCA_U32_DIVISOR]) { + u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]); + u->cu_mask |= U32_ATTR_DIVISOR; + } + + if (tb[TCA_U32_SEL]) { + u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]); + if (!u->cu_selector) + goto errout_nomem; + u->cu_mask |= U32_ATTR_SELECTOR; + } + + if (tb[TCA_U32_HASH]) { + u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]); + u->cu_mask |= U32_ATTR_HASH; + } + + if (tb[TCA_U32_CLASSID]) { + u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]); + u->cu_mask |= U32_ATTR_CLASSID; + } + + if (tb[TCA_U32_LINK]) { + u->cu_link = nla_get_u32(tb[TCA_U32_LINK]); + u->cu_mask |= U32_ATTR_LINK; + } + + if (tb[TCA_U32_ACT]) { + u->cu_act = nl_data_alloc_attr(tb[TCA_U32_ACT]); + if (!u->cu_act) + goto errout_nomem; + u->cu_mask |= U32_ATTR_ACTION; + } + + if (tb[TCA_U32_POLICE]) { + u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]); + if (!u->cu_police) + goto errout_nomem; + u->cu_mask |= U32_ATTR_POLICE; + } + + if (tb[TCA_U32_PCNT]) { + struct tc_u32_sel *sel; + int pcnt_size; + + if (!tb[TCA_U32_SEL]) { + err = -NLE_MISSING_ATTR; + goto errout; + } + + sel = u->cu_selector->d_data; + pcnt_size = sizeof(struct tc_u32_pcnt) + + (sel->nkeys * sizeof(uint64_t)); + if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) { + err = -NLE_INVAL; + goto errout; + } + + u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]); + if (!u->cu_pcnt) + goto errout_nomem; + u->cu_mask |= U32_ATTR_PCNT; + } + + if (tb[TCA_U32_INDEV]) { + nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ); + u->cu_mask |= U32_ATTR_INDEV; + } + + return 0; + +errout_nomem: + err = -NLE_NOMEM; +errout: + return err; +} + +static void u32_free_data(struct rtnl_tc *tc, void *data) +{ + struct rtnl_u32 *u = data; + + nl_data_free(u->cu_selector); + nl_data_free(u->cu_act); + nl_data_free(u->cu_police); + nl_data_free(u->cu_pcnt); +} + +static int u32_clone(void *_dst, void *_src) +{ + struct rtnl_u32 *dst = _dst, *src = _src; + + if (src->cu_selector && + !(dst->cu_selector = nl_data_clone(src->cu_selector))) + return -NLE_NOMEM; + + if (src->cu_act && !(dst->cu_act = nl_data_clone(src->cu_act))) + return -NLE_NOMEM; + + if (src->cu_police && !(dst->cu_police = nl_data_clone(src->cu_police))) + return -NLE_NOMEM; + + if (src->cu_pcnt && !(dst->cu_pcnt = nl_data_clone(src->cu_pcnt))) + return -NLE_NOMEM; + + return 0; +} + +static void u32_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_u32 *u = data; + char buf[32]; + + if (!u) + return; + + if (u->cu_mask & U32_ATTR_DIVISOR) + nl_dump(p, " divisor %u", u->cu_divisor); + else if (u->cu_mask & U32_ATTR_CLASSID) + nl_dump(p, " target %s", + rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf))); +} + +static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel, + struct rtnl_u32 *u) +{ + int i; + struct tc_u32_key *key; + + if (sel->hmask || sel->hoff) { + /* I guess this will never be used since the kernel only + * exports the selector if no divisor is set but hash offset + * and hash mask make only sense in hash filters with divisor + * set */ + nl_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask); + } + + if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) { + nl_dump(p, " offset at %u", sel->off); + + if (sel->flags & TC_U32_VAROFFSET) + nl_dump(p, " variable (at %u & 0x%x) >> %u", + sel->offoff, ntohs(sel->offmask), sel->offshift); + } + + if (sel->flags) { + int flags = sel->flags; + nl_dump(p, " <"); + +#define PRINT_FLAG(f) if (flags & TC_U32_##f) { \ + flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); } + + PRINT_FLAG(TERMINAL); + PRINT_FLAG(OFFSET); + PRINT_FLAG(VAROFFSET); + PRINT_FLAG(EAT); +#undef PRINT_FLAG + + nl_dump(p, ">"); + } + + + for (i = 0; i < sel->nkeys; i++) { + key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i; + + nl_dump(p, "\n"); + nl_dump_line(p, " match key at %s%u ", + key->offmask ? "nexthdr+" : "", key->off); + + if (key->offmask) + nl_dump(p, "[0x%u] ", key->offmask); + + nl_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val)); + + if (p->dp_type == NL_DUMP_STATS && + (u->cu_mask & U32_ATTR_PCNT)) { + struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data; + nl_dump(p, " successful %" PRIu64, pcnt->kcnts[i]); + } + } +} + +static void u32_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_u32 *u = data; + struct tc_u32_sel *s; + + if (!u) + return; + + if (!(u->cu_mask & U32_ATTR_SELECTOR)) { + nl_dump(p, "no-selector\n"); + return; + } + + s = u->cu_selector->d_data; + + nl_dump(p, "nkeys %u ", s->nkeys); + + if (u->cu_mask & U32_ATTR_HASH) + nl_dump(p, "ht key 0x%x hash 0x%u", + TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash)); + + if (u->cu_mask & U32_ATTR_LINK) + nl_dump(p, "link %u ", u->cu_link); + + if (u->cu_mask & U32_ATTR_INDEV) + nl_dump(p, "indev %s ", u->cu_indev); + + print_selector(p, s, u); + nl_dump(p, "\n"); + +#if 0 +#define U32_ATTR_ACTION 0x040 +#define U32_ATTR_POLICE 0x080 + + struct nl_data act; + struct nl_data police; +#endif +} + +static void u32_dump_stats(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_u32 *u = data; + + if (!u) + return; + + if (u->cu_mask & U32_ATTR_PCNT) { + struct tc_u32_pcnt *pc = u->cu_pcnt->d_data; + nl_dump(p, "\n"); + nl_dump_line(p, " hit %8llu count %8llu\n", + pc->rhit, pc->rcnt); + } +} + +static int u32_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) +{ + struct rtnl_u32 *u = data; + + if (!u) + return 0; + + if (u->cu_mask & U32_ATTR_DIVISOR) + NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor); + + if (u->cu_mask & U32_ATTR_HASH) + NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash); + + if (u->cu_mask & U32_ATTR_CLASSID) + NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid); + + if (u->cu_mask & U32_ATTR_LINK) + NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link); + + if (u->cu_mask & U32_ATTR_SELECTOR) + NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector); + + if (u->cu_mask & U32_ATTR_ACTION) + NLA_PUT_DATA(msg, TCA_U32_ACT, u->cu_act); + + if (u->cu_mask & U32_ATTR_POLICE) + NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police); + + if (u->cu_mask & U32_ATTR_INDEV) + NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev); + + return 0; + +nla_put_failure: + return -NLE_NOMEM; +} + +/** + * @name Attribute Modifications + * @{ + */ + +void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash, + int nodeid) +{ + uint32_t handle = (htid << 20) | (hash << 12) | nodeid; + + rtnl_tc_set_handle((struct rtnl_tc *) cls, handle ); +} + +int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid) +{ + struct rtnl_u32 *u; + + if (!(u = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + + u->cu_classid = classid; + u->cu_mask |= U32_ATTR_CLASSID; + + return 0; +} + +/** @} */ + +/** + * @name Selector Modifications + * @{ + */ + +int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags) +{ + struct tc_u32_sel *sel; + struct rtnl_u32 *u; + + if (!(u = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + + sel = u32_selector_alloc(u); + if (!sel) + return -NLE_NOMEM; + + sel->flags |= flags; + u->cu_mask |= U32_ATTR_SELECTOR; + + return 0; +} + +/** + * Append new 32-bit key to the selector + * + * @arg cls classifier to be modifier + * @arg val value to be matched (network byte-order) + * @arg mask mask to be applied before matching (network byte-order) + * @arg off offset, in bytes, to start matching + * @arg offmask offset mask + * + * General selectors define the pattern, mask and offset the pattern will be + * matched to the packet contents. Using the general selectors you can match + * virtually any single bit in the IP (or upper layer) header. + * +*/ +int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask, + int off, int offmask) +{ + struct tc_u32_sel *sel; + struct rtnl_u32 *u; + int err; + + if (!(u = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + + sel = u32_selector_alloc(u); + if (!sel) + return -NLE_NOMEM; + + err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key)); + if (err < 0) + return err; + + /* the selector might have been moved by realloc */ + sel = u32_selector(u); + + sel->keys[sel->nkeys].mask = mask; + sel->keys[sel->nkeys].val = val & mask; + sel->keys[sel->nkeys].off = off; + sel->keys[sel->nkeys].offmask = offmask; + sel->nkeys++; + u->cu_mask |= U32_ATTR_SELECTOR; + + return 0; +} + +int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask, + int off, int offmask) +{ + int shift = 24 - 8 * (off & 3); + + return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift), + htonl((uint32_t)mask << shift), + off & ~3, offmask); +} + +/** + * Append new selector key to match a 16-bit number + * + * @arg cls classifier to be modified + * @arg val value to be matched (host byte-order) + * @arg mask mask to be applied before matching (host byte-order) + * @arg off offset, in bytes, to start matching + * @arg offmask offset mask +*/ +int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask, + int off, int offmask) +{ + int shift = ((off & 3) == 0 ? 16 : 0); + if (off % 2) + return -NLE_INVAL; + + return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift), + htonl((uint32_t)mask << shift), + off & ~3, offmask); +} + +/** + * Append new selector key to match a 32-bit number + * + * @arg cls classifier to be modified + * @arg val value to be matched (host byte-order) + * @arg mask mask to be applied before matching (host byte-order) + * @arg off offset, in bytes, to start matching + * @arg offmask offset mask +*/ +int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask, + int off, int offmask) +{ + return rtnl_u32_add_key(cls, htonl(val), htonl(mask), + off & ~3, offmask); +} + +int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr, + uint8_t bitmask, int off, int offmask) +{ + uint32_t mask = 0xFFFFFFFF << (32 - bitmask); + return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask); +} + +int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr, + uint8_t bitmask, int off, int offmask) +{ + int i, err; + + for (i = 1; i <= 4; i++) { + if (32 * i - bitmask <= 0) { + if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1], + 0xFFFFFFFF, off+4*(i-1), offmask)) < 0) + return err; + } + else if (32 * i - bitmask < 32) { + uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask); + if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1], + htonl(mask), off+4*(i-1), offmask)) < 0) + return err; + } + /* otherwise, if (32*i - bitmask >= 32) no key is generated */ + } + + return 0; +} + +/** @} */ + +static struct rtnl_tc_ops u32_ops = { + .to_kind = "u32", + .to_type = RTNL_TC_TYPE_CLS, + .to_size = sizeof(struct rtnl_u32), + .to_msg_parser = u32_msg_parser, + .to_free_data = u32_free_data, + .to_clone = u32_clone, + .to_msg_fill = u32_msg_fill, + .to_dump = { + [NL_DUMP_LINE] = u32_dump_line, + [NL_DUMP_DETAILS] = u32_dump_details, + [NL_DUMP_STATS] = u32_dump_stats, + }, +}; + +static void __init u32_init(void) +{ + rtnl_tc_register(&u32_ops); +} + +static void __exit u32_exit(void) +{ + rtnl_tc_unregister(&u32_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/link.c b/libnetwork/libnl3/lib/route/link.c new file mode 100644 index 0000000..e486b3f --- /dev/null +++ b/libnetwork/libnl3/lib/route/link.c @@ -0,0 +1,2342 @@ +/* + * lib/route/link.c Links (Interfaces) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +/** + * @ingroup rtnl + * @defgroup link Links (Interfaces) + * + * @details + * @route_doc{route_link, Link Documentation} + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define LINK_ATTR_MTU 0x0001 +#define LINK_ATTR_LINK 0x0002 +#define LINK_ATTR_TXQLEN 0x0004 +#define LINK_ATTR_WEIGHT 0x0008 +#define LINK_ATTR_MASTER 0x0010 +#define LINK_ATTR_QDISC 0x0020 +#define LINK_ATTR_MAP 0x0040 +#define LINK_ATTR_ADDR 0x0080 +#define LINK_ATTR_BRD 0x0100 +#define LINK_ATTR_FLAGS 0x0200 +#define LINK_ATTR_IFNAME 0x0400 +#define LINK_ATTR_IFINDEX 0x0800 +#define LINK_ATTR_FAMILY 0x1000 +#define LINK_ATTR_ARPTYPE 0x2000 +#define LINK_ATTR_STATS 0x4000 +#define LINK_ATTR_CHANGE 0x8000 +#define LINK_ATTR_OPERSTATE 0x10000 +#define LINK_ATTR_LINKMODE 0x20000 +#define LINK_ATTR_LINKINFO 0x40000 +#define LINK_ATTR_IFALIAS 0x80000 +#define LINK_ATTR_NUM_VF 0x100000 + +static struct nl_cache_ops rtnl_link_ops; +static struct nl_object_ops link_obj_ops; +/** @endcond */ + +static struct rtnl_link_af_ops *af_lookup_and_alloc(struct rtnl_link *link, + int family) +{ + struct rtnl_link_af_ops *af_ops; + void *data; + + af_ops = rtnl_link_af_ops_lookup(family); + if (!af_ops) + return NULL; + + if (!(data = rtnl_link_af_alloc(link, af_ops))) + return NULL; + + return af_ops; +} + +static int af_free(struct rtnl_link *link, struct rtnl_link_af_ops *ops, + void *data, void *arg) +{ + if (ops->ao_free) + ops->ao_free(link, data); + + rtnl_link_af_ops_put(ops); + + return 0; +} + +static int af_clone(struct rtnl_link *link, struct rtnl_link_af_ops *ops, + void *data, void *arg) +{ + struct rtnl_link *dst = arg; + + if (ops->ao_clone && + !(dst->l_af_data[ops->ao_family] = ops->ao_clone(dst, data))) + return -NLE_NOMEM; + + return 0; +} + +static int af_fill(struct rtnl_link *link, struct rtnl_link_af_ops *ops, + void *data, void *arg) +{ + struct nl_msg *msg = arg; + struct nlattr *af_attr; + int err; + + if (!ops->ao_fill_af) + return 0; + + if (!(af_attr = nla_nest_start(msg, ops->ao_family))) + return -NLE_MSGSIZE; + + if ((err = ops->ao_fill_af(link, arg, data)) < 0) + return err; + + nla_nest_end(msg, af_attr); + + return 0; +} + +static int af_dump_line(struct rtnl_link *link, struct rtnl_link_af_ops *ops, + void *data, void *arg) +{ + struct nl_dump_params *p = arg; + + if (ops->ao_dump[NL_DUMP_LINE]) + ops->ao_dump[NL_DUMP_LINE](link, p, data); + + return 0; +} + +static int af_dump_details(struct rtnl_link *link, struct rtnl_link_af_ops *ops, + void *data, void *arg) +{ + struct nl_dump_params *p = arg; + + if (ops->ao_dump[NL_DUMP_DETAILS]) + ops->ao_dump[NL_DUMP_DETAILS](link, p, data); + + return 0; +} + +static int af_dump_stats(struct rtnl_link *link, struct rtnl_link_af_ops *ops, + void *data, void *arg) +{ + struct nl_dump_params *p = arg; + + if (ops->ao_dump[NL_DUMP_STATS]) + ops->ao_dump[NL_DUMP_STATS](link, p, data); + + return 0; +} + +static int do_foreach_af(struct rtnl_link *link, + int (*cb)(struct rtnl_link *, + struct rtnl_link_af_ops *, void *, void *), + void *arg) +{ + int i, err; + + for (i = 0; i < AF_MAX; i++) { + if (link->l_af_data[i]) { + struct rtnl_link_af_ops *ops; + + if (!(ops = rtnl_link_af_ops_lookup(i))) + BUG(); + + if ((err = cb(link, ops, link->l_af_data[i], arg)) < 0) + return err; + } + } + + return 0; +} + +static void release_link_info(struct rtnl_link *link) +{ + struct rtnl_link_info_ops *io = link->l_info_ops; + + if (io != NULL) { + if (io->io_free) + io->io_free(link); + rtnl_link_info_ops_put(io); + link->l_info_ops = NULL; + } +} + +static void link_free_data(struct nl_object *c) +{ + struct rtnl_link *link = nl_object_priv(c); + + if (link) { + struct rtnl_link_info_ops *io; + + if ((io = link->l_info_ops) != NULL) + release_link_info(link); + + nl_addr_put(link->l_addr); + nl_addr_put(link->l_bcast); + + free(link->l_ifalias); + + do_foreach_af(link, af_free, NULL); + } +} + +static int link_clone(struct nl_object *_dst, struct nl_object *_src) +{ + struct rtnl_link *dst = nl_object_priv(_dst); + struct rtnl_link *src = nl_object_priv(_src); + int err; + + if (src->l_addr) + if (!(dst->l_addr = nl_addr_clone(src->l_addr))) + return -NLE_NOMEM; + + if (src->l_bcast) + if (!(dst->l_bcast = nl_addr_clone(src->l_bcast))) + return -NLE_NOMEM; + + if (src->l_ifalias) + if (!(dst->l_ifalias = strdup(src->l_ifalias))) + return -NLE_NOMEM; + + if (src->l_info_ops && src->l_info_ops->io_clone) { + err = src->l_info_ops->io_clone(dst, src); + if (err < 0) + return err; + } + + if ((err = do_foreach_af(src, af_clone, dst)) < 0) + return err; + + return 0; +} + +static struct nla_policy link_policy[IFLA_MAX+1] = { + [IFLA_IFNAME] = { .type = NLA_STRING, + .maxlen = IFNAMSIZ }, + [IFLA_MTU] = { .type = NLA_U32 }, + [IFLA_TXQLEN] = { .type = NLA_U32 }, + [IFLA_LINK] = { .type = NLA_U32 }, + [IFLA_WEIGHT] = { .type = NLA_U32 }, + [IFLA_MASTER] = { .type = NLA_U32 }, + [IFLA_OPERSTATE]= { .type = NLA_U8 }, + [IFLA_LINKMODE] = { .type = NLA_U8 }, + [IFLA_LINKINFO] = { .type = NLA_NESTED }, + [IFLA_QDISC] = { .type = NLA_STRING, + .maxlen = IFQDISCSIZ }, + [IFLA_STATS] = { .minlen = sizeof(struct rtnl_link_stats) }, + [IFLA_STATS64] = { .minlen = sizeof(struct rtnl_link_stats64) }, + [IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) }, + [IFLA_IFALIAS] = { .type = NLA_STRING, .maxlen = IFALIASZ }, + [IFLA_NUM_VF] = { .type = NLA_U32 }, + [IFLA_AF_SPEC] = { .type = NLA_NESTED }, +}; + +static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = { + [IFLA_INFO_KIND] = { .type = NLA_STRING }, + [IFLA_INFO_DATA] = { .type = NLA_NESTED }, + [IFLA_INFO_XSTATS] = { .type = NLA_NESTED }, +}; + +static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *n, struct nl_parser_param *pp) +{ + struct rtnl_link *link; + struct ifinfomsg *ifi; + struct nlattr *tb[IFLA_MAX+1]; + struct rtnl_link_af_ops *af_ops = NULL; + int err, family; + + link = rtnl_link_alloc(); + if (link == NULL) { + err = -NLE_NOMEM; + goto errout; + } + + link->ce_msgtype = n->nlmsg_type; + + if (!nlmsg_valid_hdr(n, sizeof(*ifi))) + return -NLE_MSG_TOOSHORT; + + ifi = nlmsg_data(n); + link->l_family = family = ifi->ifi_family; + link->l_arptype = ifi->ifi_type; + link->l_index = ifi->ifi_index; + link->l_flags = ifi->ifi_flags; + link->l_change = ifi->ifi_change; + link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY | + LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX | + LINK_ATTR_FLAGS | LINK_ATTR_CHANGE); + + if ((af_ops = af_lookup_and_alloc(link, family))) { + if (af_ops->ao_protinfo_policy) { + memcpy(&link_policy[IFLA_PROTINFO], + af_ops->ao_protinfo_policy, + sizeof(struct nla_policy)); + } + } + + err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy); + if (err < 0) + goto errout; + + if (tb[IFLA_IFNAME] == NULL) { + err = -NLE_MISSING_ATTR; + goto errout; + } + + nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ); + + + if (tb[IFLA_STATS]) { + struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]); + + link->l_stats[RTNL_LINK_RX_PACKETS] = st->rx_packets; + link->l_stats[RTNL_LINK_TX_PACKETS] = st->tx_packets; + link->l_stats[RTNL_LINK_RX_BYTES] = st->rx_bytes; + link->l_stats[RTNL_LINK_TX_BYTES] = st->tx_bytes; + link->l_stats[RTNL_LINK_RX_ERRORS] = st->rx_errors; + link->l_stats[RTNL_LINK_TX_ERRORS] = st->tx_errors; + link->l_stats[RTNL_LINK_RX_DROPPED] = st->rx_dropped; + link->l_stats[RTNL_LINK_TX_DROPPED] = st->tx_dropped; + link->l_stats[RTNL_LINK_MULTICAST] = st->multicast; + link->l_stats[RTNL_LINK_COLLISIONS] = st->collisions; + + link->l_stats[RTNL_LINK_RX_LEN_ERR] = st->rx_length_errors; + link->l_stats[RTNL_LINK_RX_OVER_ERR] = st->rx_over_errors; + link->l_stats[RTNL_LINK_RX_CRC_ERR] = st->rx_crc_errors; + link->l_stats[RTNL_LINK_RX_FRAME_ERR] = st->rx_frame_errors; + link->l_stats[RTNL_LINK_RX_FIFO_ERR] = st->rx_fifo_errors; + link->l_stats[RTNL_LINK_RX_MISSED_ERR] = st->rx_missed_errors; + + link->l_stats[RTNL_LINK_TX_ABORT_ERR] = st->tx_aborted_errors; + link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors; + link->l_stats[RTNL_LINK_TX_FIFO_ERR] = st->tx_fifo_errors; + link->l_stats[RTNL_LINK_TX_HBEAT_ERR] = st->tx_heartbeat_errors; + link->l_stats[RTNL_LINK_TX_WIN_ERR] = st->tx_window_errors; + + link->l_stats[RTNL_LINK_RX_COMPRESSED] = st->rx_compressed; + link->l_stats[RTNL_LINK_TX_COMPRESSED] = st->tx_compressed; + + link->ce_mask |= LINK_ATTR_STATS; + } + + if (tb[IFLA_STATS64]) { + /* + * This structure contains 64bit parameters, and per the + * documentation in lib/attr.c, must not be accessed + * directly (because of alignment to 4 instead of 8). + * Therefore, copy the data to the stack and access it from + * there, where it will be aligned to 8. + */ + struct rtnl_link_stats64 st; + + nla_memcpy(&st, tb[IFLA_STATS64], + sizeof(struct rtnl_link_stats64)); + + link->l_stats[RTNL_LINK_RX_PACKETS] = st.rx_packets; + link->l_stats[RTNL_LINK_TX_PACKETS] = st.tx_packets; + link->l_stats[RTNL_LINK_RX_BYTES] = st.rx_bytes; + link->l_stats[RTNL_LINK_TX_BYTES] = st.tx_bytes; + link->l_stats[RTNL_LINK_RX_ERRORS] = st.rx_errors; + link->l_stats[RTNL_LINK_TX_ERRORS] = st.tx_errors; + link->l_stats[RTNL_LINK_RX_DROPPED] = st.rx_dropped; + link->l_stats[RTNL_LINK_TX_DROPPED] = st.tx_dropped; + link->l_stats[RTNL_LINK_MULTICAST] = st.multicast; + link->l_stats[RTNL_LINK_COLLISIONS] = st.collisions; + + link->l_stats[RTNL_LINK_RX_LEN_ERR] = st.rx_length_errors; + link->l_stats[RTNL_LINK_RX_OVER_ERR] = st.rx_over_errors; + link->l_stats[RTNL_LINK_RX_CRC_ERR] = st.rx_crc_errors; + link->l_stats[RTNL_LINK_RX_FRAME_ERR] = st.rx_frame_errors; + link->l_stats[RTNL_LINK_RX_FIFO_ERR] = st.rx_fifo_errors; + link->l_stats[RTNL_LINK_RX_MISSED_ERR] = st.rx_missed_errors; + + link->l_stats[RTNL_LINK_TX_ABORT_ERR] = st.tx_aborted_errors; + link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st.tx_carrier_errors; + link->l_stats[RTNL_LINK_TX_FIFO_ERR] = st.tx_fifo_errors; + link->l_stats[RTNL_LINK_TX_HBEAT_ERR] = st.tx_heartbeat_errors; + link->l_stats[RTNL_LINK_TX_WIN_ERR] = st.tx_window_errors; + + link->l_stats[RTNL_LINK_RX_COMPRESSED] = st.rx_compressed; + link->l_stats[RTNL_LINK_TX_COMPRESSED] = st.tx_compressed; + + link->ce_mask |= LINK_ATTR_STATS; + } + + if (tb[IFLA_TXQLEN]) { + link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]); + link->ce_mask |= LINK_ATTR_TXQLEN; + } + + if (tb[IFLA_MTU]) { + link->l_mtu = nla_get_u32(tb[IFLA_MTU]); + link->ce_mask |= LINK_ATTR_MTU; + } + + if (tb[IFLA_ADDRESS]) { + link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC); + if (link->l_addr == NULL) { + err = -NLE_NOMEM; + goto errout; + } + nl_addr_set_family(link->l_addr, + nl_addr_guess_family(link->l_addr)); + link->ce_mask |= LINK_ATTR_ADDR; + } + + if (tb[IFLA_BROADCAST]) { + link->l_bcast = nl_addr_alloc_attr(tb[IFLA_BROADCAST], + AF_UNSPEC); + if (link->l_bcast == NULL) { + err = -NLE_NOMEM; + goto errout; + } + nl_addr_set_family(link->l_bcast, + nl_addr_guess_family(link->l_bcast)); + link->ce_mask |= LINK_ATTR_BRD; + } + + if (tb[IFLA_LINK]) { + link->l_link = nla_get_u32(tb[IFLA_LINK]); + link->ce_mask |= LINK_ATTR_LINK; + } + + if (tb[IFLA_WEIGHT]) { + link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]); + link->ce_mask |= LINK_ATTR_WEIGHT; + } + + if (tb[IFLA_QDISC]) { + nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ); + link->ce_mask |= LINK_ATTR_QDISC; + } + + if (tb[IFLA_MAP]) { + nla_memcpy(&link->l_map, tb[IFLA_MAP], + sizeof(struct rtnl_link_ifmap)); + link->ce_mask |= LINK_ATTR_MAP; + } + + if (tb[IFLA_MASTER]) { + link->l_master = nla_get_u32(tb[IFLA_MASTER]); + link->ce_mask |= LINK_ATTR_MASTER; + } + + if (tb[IFLA_OPERSTATE]) { + link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]); + link->ce_mask |= LINK_ATTR_OPERSTATE; + } + + if (tb[IFLA_LINKMODE]) { + link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]); + link->ce_mask |= LINK_ATTR_LINKMODE; + } + + if (tb[IFLA_IFALIAS]) { + link->l_ifalias = nla_strdup(tb[IFLA_IFALIAS]); + if (link->l_ifalias == NULL) { + err = -NLE_NOMEM; + goto errout; + } + link->ce_mask |= LINK_ATTR_IFALIAS; + } + + if (tb[IFLA_NUM_VF]) { + link->l_num_vf = nla_get_u32(tb[IFLA_NUM_VF]); + link->ce_mask |= LINK_ATTR_NUM_VF; + } + + if (tb[IFLA_LINKINFO]) { + struct nlattr *li[IFLA_INFO_MAX+1]; + + err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], + link_info_policy); + if (err < 0) + goto errout; + + if (li[IFLA_INFO_KIND]) { + struct rtnl_link_info_ops *ops; + char *kind; + + kind = nla_get_string(li[IFLA_INFO_KIND]); + ops = rtnl_link_info_ops_lookup(kind); + link->l_info_ops = ops; + + if (ops && ops->io_parse && + (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) { + err = ops->io_parse(link, li[IFLA_INFO_DATA], + li[IFLA_INFO_XSTATS]); + if (err < 0) + goto errout; + } else { + /* XXX: Warn about unparsed info? */ + } + } + } + + if (tb[IFLA_PROTINFO] && af_ops && af_ops->ao_parse_protinfo) { + err = af_ops->ao_parse_protinfo(link, tb[IFLA_PROTINFO], + link->l_af_data[link->l_family]); + if (err < 0) + goto errout; + } + + if (tb[IFLA_AF_SPEC]) { + struct nlattr *af_attr; + int remaining; + + nla_for_each_nested(af_attr, tb[IFLA_AF_SPEC], remaining) { + af_ops = af_lookup_and_alloc(link, nla_type(af_attr)); + if (af_ops && af_ops->ao_parse_af) { + char *af_data = link->l_af_data[nla_type(af_attr)]; + + err = af_ops->ao_parse_af(link, af_attr, af_data); + + rtnl_link_af_ops_put(af_ops); + + if (err < 0) + goto errout; + } + + } + } + + err = pp->pp_cb((struct nl_object *) link, pp); +errout: + rtnl_link_af_ops_put(af_ops); + rtnl_link_put(link); + return err; +} + +static int link_event_filter(struct nl_cache *cache, struct nl_object *obj) +{ + struct rtnl_link *link = (struct rtnl_link *) obj; + + /* + * Ignore bridging messages when keeping the cache manager up to date. + */ + if (link->l_family == AF_BRIDGE) + return NL_SKIP; + + return NL_OK; +} + +static int link_request_update(struct nl_cache *cache, struct nl_sock *sk) +{ + int family = cache->c_iarg1; + + return nl_rtgen_request(sk, RTM_GETLINK, family, NLM_F_DUMP); +} + +static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p) +{ + char buf[128]; + struct nl_cache *cache = dp_cache(obj); + struct rtnl_link *link = (struct rtnl_link *) obj; + + nl_dump_line(p, "%s %s ", link->l_name, + nl_llproto2str(link->l_arptype, buf, sizeof(buf))); + + if (link->l_addr && !nl_addr_iszero(link->l_addr)) + nl_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf))); + + if (link->ce_mask & LINK_ATTR_MASTER) { + struct rtnl_link *master = rtnl_link_get(cache, link->l_master); + nl_dump(p, "master %s ", master ? master->l_name : "inv"); + if (master) + rtnl_link_put(master); + } + + rtnl_link_flags2str(link->l_flags, buf, sizeof(buf)); + if (buf[0]) + nl_dump(p, "<%s> ", buf); + + if (link->ce_mask & LINK_ATTR_LINK) { + struct rtnl_link *ll = rtnl_link_get(cache, link->l_link); + nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE"); + if (ll) + rtnl_link_put(ll); + } + + if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE]) + link->l_info_ops->io_dump[NL_DUMP_LINE](link, p); + + do_foreach_af(link, af_dump_line, p); + + nl_dump(p, "\n"); +} + +static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p) +{ + struct rtnl_link *link = (struct rtnl_link *) obj; + char buf[64]; + + link_dump_line(obj, p); + + nl_dump_line(p, " mtu %u ", link->l_mtu); + nl_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight); + + if (link->ce_mask & LINK_ATTR_QDISC) + nl_dump(p, "qdisc %s ", link->l_qdisc); + + if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq) + nl_dump(p, "irq %u ", link->l_map.lm_irq); + + if (link->ce_mask & LINK_ATTR_IFINDEX) + nl_dump(p, "index %u ", link->l_index); + + + nl_dump(p, "\n"); + + if (link->ce_mask & LINK_ATTR_IFALIAS) + nl_dump_line(p, " alias %s\n", link->l_ifalias); + + nl_dump_line(p, " "); + + if (link->ce_mask & LINK_ATTR_BRD) + nl_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf, + sizeof(buf))); + + if ((link->ce_mask & LINK_ATTR_OPERSTATE) && + link->l_operstate != IF_OPER_UNKNOWN) { + rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf)); + nl_dump(p, "state %s ", buf); + } + + if (link->ce_mask & LINK_ATTR_NUM_VF) + nl_dump(p, "num-vf %u ", link->l_num_vf); + + nl_dump(p, "mode %s\n", + rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf))); + + if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS]) + link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p); + + do_foreach_af(link, af_dump_details, p); +} + +static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p) +{ + struct rtnl_link *link = (struct rtnl_link *) obj; + char *unit, fmt[64]; + float res; + + link_dump_details(obj, p); + + nl_dump_line(p, " Stats: bytes packets errors " + " dropped fifo-err compressed\n"); + + res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit); + + strcpy(fmt, " RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n"); + fmt[9] = *unit == 'B' ? '9' : '7'; + + nl_dump_line(p, fmt, res, unit, + link->l_stats[RTNL_LINK_RX_PACKETS], + link->l_stats[RTNL_LINK_RX_ERRORS], + link->l_stats[RTNL_LINK_RX_DROPPED], + link->l_stats[RTNL_LINK_RX_FIFO_ERR], + link->l_stats[RTNL_LINK_RX_COMPRESSED]); + + res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit); + + strcpy(fmt, " TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n"); + fmt[9] = *unit == 'B' ? '9' : '7'; + + nl_dump_line(p, fmt, res, unit, + link->l_stats[RTNL_LINK_TX_PACKETS], + link->l_stats[RTNL_LINK_TX_ERRORS], + link->l_stats[RTNL_LINK_TX_DROPPED], + link->l_stats[RTNL_LINK_TX_FIFO_ERR], + link->l_stats[RTNL_LINK_TX_COMPRESSED]); + + nl_dump_line(p, " Errors: length over crc " + " frame missed multicast\n"); + + nl_dump_line(p, " RX %10" PRIu64 " %10" PRIu64 " %10" + PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" + PRIu64 "\n", + link->l_stats[RTNL_LINK_RX_LEN_ERR], + link->l_stats[RTNL_LINK_RX_OVER_ERR], + link->l_stats[RTNL_LINK_RX_CRC_ERR], + link->l_stats[RTNL_LINK_RX_FRAME_ERR], + link->l_stats[RTNL_LINK_RX_MISSED_ERR], + link->l_stats[RTNL_LINK_MULTICAST]); + + nl_dump_line(p, " aborted carrier heartbeat " + " window collision\n"); + + nl_dump_line(p, " TX %10" PRIu64 " %10" PRIu64 " %10" + PRIu64 " %10" PRIu64 " %10" PRIu64 "\n", + link->l_stats[RTNL_LINK_TX_ABORT_ERR], + link->l_stats[RTNL_LINK_TX_CARRIER_ERR], + link->l_stats[RTNL_LINK_TX_HBEAT_ERR], + link->l_stats[RTNL_LINK_TX_WIN_ERR], + link->l_stats[RTNL_LINK_COLLISIONS]); + + if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS]) + link->l_info_ops->io_dump[NL_DUMP_STATS](link, p); + + do_foreach_af(link, af_dump_stats, p); +} + +#if 0 +static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb) +{ + struct rtnl_link *l = (struct rtnl_link *) a; + struct nl_cache *c = dp_cache(a); + int nevents = 0; + + if (l->l_change == ~0U) { + if (l->ce_msgtype == RTM_NEWLINK) + cb->le_register(l); + else + cb->le_unregister(l); + + return 1; + } + + if (l->l_change & IFF_SLAVE) { + if (l->l_flags & IFF_SLAVE) { + struct rtnl_link *m = rtnl_link_get(c, l->l_master); + cb->le_new_bonding(l, m); + if (m) + rtnl_link_put(m); + } else + cb->le_cancel_bonding(l); + } + +#if 0 + if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING) + dp_dump_line(p, line++, "link %s changed state to %s.\n", + l->l_name, l->l_flags & IFF_UP ? "up" : "down"); + + if (l->l_change & IFF_PROMISC) { + dp_new_line(p, line++); + dp_dump(p, "link %s %s promiscuous mode.\n", + l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left"); + } + + if (line == 0) + dp_dump_line(p, line++, "link %s sent unknown event.\n", + l->l_name); +#endif + + return nevents; +} +#endif + +static int link_compare(struct nl_object *_a, struct nl_object *_b, + uint32_t attrs, int flags) +{ + struct rtnl_link *a = (struct rtnl_link *) _a; + struct rtnl_link *b = (struct rtnl_link *) _b; + int diff = 0; + +#define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR) + + diff |= LINK_DIFF(IFINDEX, a->l_index != b->l_index); + diff |= LINK_DIFF(MTU, a->l_mtu != b->l_mtu); + diff |= LINK_DIFF(LINK, a->l_link != b->l_link); + diff |= LINK_DIFF(TXQLEN, a->l_txqlen != b->l_txqlen); + diff |= LINK_DIFF(WEIGHT, a->l_weight != b->l_weight); + diff |= LINK_DIFF(MASTER, a->l_master != b->l_master); + diff |= LINK_DIFF(FAMILY, a->l_family != b->l_family); + diff |= LINK_DIFF(OPERSTATE, a->l_operstate != b->l_operstate); + diff |= LINK_DIFF(LINKMODE, a->l_linkmode != b->l_linkmode); + diff |= LINK_DIFF(QDISC, strcmp(a->l_qdisc, b->l_qdisc)); + diff |= LINK_DIFF(IFNAME, strcmp(a->l_name, b->l_name)); + diff |= LINK_DIFF(ADDR, nl_addr_cmp(a->l_addr, b->l_addr)); + diff |= LINK_DIFF(BRD, nl_addr_cmp(a->l_bcast, b->l_bcast)); + diff |= LINK_DIFF(IFALIAS, strcmp(a->l_ifalias, b->l_ifalias)); + diff |= LINK_DIFF(NUM_VF, a->l_num_vf != b->l_num_vf); + + if (flags & LOOSE_COMPARISON) + diff |= LINK_DIFF(FLAGS, + (a->l_flags ^ b->l_flags) & b->l_flag_mask); + else + diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags); + +#undef LINK_DIFF + + return diff; +} + +static const struct trans_tbl link_attrs[] = { + __ADD(LINK_ATTR_MTU, mtu) + __ADD(LINK_ATTR_LINK, link) + __ADD(LINK_ATTR_TXQLEN, txqlen) + __ADD(LINK_ATTR_WEIGHT, weight) + __ADD(LINK_ATTR_MASTER, master) + __ADD(LINK_ATTR_QDISC, qdisc) + __ADD(LINK_ATTR_MAP, map) + __ADD(LINK_ATTR_ADDR, address) + __ADD(LINK_ATTR_BRD, broadcast) + __ADD(LINK_ATTR_FLAGS, flags) + __ADD(LINK_ATTR_IFNAME, name) + __ADD(LINK_ATTR_IFINDEX, ifindex) + __ADD(LINK_ATTR_FAMILY, family) + __ADD(LINK_ATTR_ARPTYPE, arptype) + __ADD(LINK_ATTR_STATS, stats) + __ADD(LINK_ATTR_CHANGE, change) + __ADD(LINK_ATTR_OPERSTATE, operstate) + __ADD(LINK_ATTR_LINKMODE, linkmode) + __ADD(LINK_ATTR_IFALIAS, ifalias) + __ADD(LINK_ATTR_NUM_VF, num_vf) +}; + +static char *link_attrs2str(int attrs, char *buf, size_t len) +{ + return __flags2str(attrs, buf, len, link_attrs, + ARRAY_SIZE(link_attrs)); +} + +/** + * @name Get / List + * @{ + */ + + +/** + * Allocate link cache and fill in all configured links. + * @arg sk Netlink socket. + * @arg family Link address family or AF_UNSPEC + * @arg result Pointer to store resulting cache. + * + * Allocates and initializes a new link cache. A netlink message is sent to + * the kernel requesting a full dump of all configured links. The returned + * messages are parsed and filled into the cache. If the operation succeeds + * the resulting cache will a link object for each link configured in the + * kernel. + * + * If \c family is set to an address family other than \c AF_UNSPEC the + * contents of the cache can be limited to a specific address family. + * Currently the following address families are supported: + * - AF_BRIDGE + * - AF_INET6 + * + * @route_doc{link_list, Get List of Links} + * @see rtnl_link_get() + * @see rtnl_link_get_by_name() + * @return 0 on success or a negative error code. + */ +int rtnl_link_alloc_cache(struct nl_sock *sk, int family, struct nl_cache **result) +{ + struct nl_cache * cache; + int err; + + cache = nl_cache_alloc(&rtnl_link_ops); + if (!cache) + return -NLE_NOMEM; + + cache->c_iarg1 = family; + + if (sk && (err = nl_cache_refill(sk, cache)) < 0) { + nl_cache_free(cache); + return err; + } + + *result = cache; + return 0; +} + +/** + * Lookup link in cache by interface index + * @arg cache Link cache + * @arg ifindex Interface index + * + * Searches through the provided cache looking for a link with matching + * interface index. + * + * @attention The reference counter of the returned link object will be + * incremented. Use rtnl_link_put() to release the reference. + * + * @route_doc{link_list, Get List of Links} + * @see rtnl_link_get_by_name() + * @return Link object or NULL if no match was found. + */ +struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex) +{ + struct rtnl_link *link; + + if (cache->c_ops != &rtnl_link_ops) + return NULL; + + nl_list_for_each_entry(link, &cache->c_items, ce_list) { + if (link->l_index == ifindex) { + nl_object_get((struct nl_object *) link); + return link; + } + } + + return NULL; +} + +/** + * Lookup link in cache by link name + * @arg cache Link cache + * @arg name Name of link + * + * Searches through the provided cache looking for a link with matching + * link name + * + * @attention The reference counter of the returned link object will be + * incremented. Use rtnl_link_put() to release the reference. + * + * @route_doc{link_list, Get List of Links} + * @see rtnl_link_get() + * @return Link object or NULL if no match was found. + */ +struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache, + const char *name) +{ + struct rtnl_link *link; + + if (cache->c_ops != &rtnl_link_ops) + return NULL; + + nl_list_for_each_entry(link, &cache->c_items, ce_list) { + if (!strcmp(name, link->l_name)) { + nl_object_get((struct nl_object *) link); + return link; + } + } + + return NULL; +} + +/** + * Construct RTM_GETLINK netlink message + * @arg ifindex Interface index + * @arg name Name of link + * @arg result Pointer to store resulting netlink message + * + * The behaviour of this function is identical to rtnl_link_get_kernel() + * with the exception that it will not send the message but return it in + * the provided return pointer instead. + * + * @see rtnl_link_get_kernel() + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_build_get_request(int ifindex, const char *name, + struct nl_msg **result) +{ + struct ifinfomsg ifi; + struct nl_msg *msg; + + if (ifindex <= 0 && !name) { + APPBUG("ifindex or name must be specified"); + return -NLE_MISSING_ATTR; + } + + memset(&ifi, 0, sizeof(ifi)); + + if (!(msg = nlmsg_alloc_simple(RTM_GETLINK, 0))) + return -NLE_NOMEM; + + if (ifindex > 0) + ifi.ifi_index = ifindex; + + if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + if (name) + NLA_PUT_STRING(msg, IFLA_IFNAME, name); + + *result = msg; + return 0; + +nla_put_failure: + nlmsg_free(msg); + return -NLE_MSGSIZE; +} + +/** + * Get a link object directly from kernel + * @arg sk Netlink socket + * @arg ifindex Interface index + * @arg name Name of link + * @arg result Pointer to store resulting link object + * + * This function builds a \c RTM_GETLINK netlink message to request + * a specific link directly from the kernel. The returned answer is + * parsed into a struct rtnl_link object and returned via the result + * pointer or -NLE_OBJ_NOTFOUND is returned if no matching link was + * found. + * + * @route_doc{link_direct_lookup, Lookup Single Link (Direct Lookup)} + * @return 0 on success or a negative error code. + */ +int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name, + struct rtnl_link **result) +{ + struct nl_msg *msg = NULL; + struct nl_object *obj; + int err; + + if ((err = rtnl_link_build_get_request(ifindex, name, &msg)) < 0) + return err; + + err = nl_send_auto(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + if ((err = nl_pickup(sk, link_msg_parser, &obj)) < 0) + return err; + + /* We have used link_msg_parser(), object is definitely a link */ + *result = (struct rtnl_link *) obj; + + /* If an object has been returned, we also need to wait for the ACK */ + if (err == 0 && obj) + nl_wait_for_ack(sk); + + return 0; +} + +/** + * Translate interface index to corresponding link name + * @arg cache Link cache + * @arg ifindex Interface index + * @arg dst String to store name + * @arg len Length of destination string + * + * Translates the specified interface index to the corresponding + * link name and stores the name in the destination string. + * + * @route_doc{link_translate_ifindex, Translating interface index to link name} + * @see rtnl_link_name2i() + * @return Name of link or NULL if no match was found. + */ +char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst, + size_t len) +{ + struct rtnl_link *link = rtnl_link_get(cache, ifindex); + + if (link) { + strncpy(dst, link->l_name, len - 1); + rtnl_link_put(link); + return dst; + } + + return NULL; +} + +/** + * Translate link name to corresponding interface index + * @arg cache Link cache + * @arg name Name of link + * + * @route_doc{link_translate_ifindex, Translating interface index to link name} + * @see rtnl_link_i2name() + * @return Interface index or 0 if no match was found. + */ +int rtnl_link_name2i(struct nl_cache *cache, const char *name) +{ + int ifindex = 0; + struct rtnl_link *link; + + link = rtnl_link_get_by_name(cache, name); + if (link) { + ifindex = link->l_index; + rtnl_link_put(link); + } + + return ifindex; +} + +/** @} */ + +static int build_link_msg(int cmd, struct ifinfomsg *hdr, + struct rtnl_link *link, int flags, struct nl_msg **result) +{ + struct nl_msg *msg; + struct nlattr *af_spec; + + msg = nlmsg_alloc_simple(cmd, flags); + if (!msg) + return -NLE_NOMEM; + + if (nlmsg_append(msg, hdr, sizeof(*hdr), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + if (link->ce_mask & LINK_ATTR_ADDR) + NLA_PUT_ADDR(msg, IFLA_ADDRESS, link->l_addr); + + if (link->ce_mask & LINK_ATTR_BRD) + NLA_PUT_ADDR(msg, IFLA_BROADCAST, link->l_bcast); + + if (link->ce_mask & LINK_ATTR_MTU) + NLA_PUT_U32(msg, IFLA_MTU, link->l_mtu); + + if (link->ce_mask & LINK_ATTR_TXQLEN) + NLA_PUT_U32(msg, IFLA_TXQLEN, link->l_txqlen); + + if (link->ce_mask & LINK_ATTR_WEIGHT) + NLA_PUT_U32(msg, IFLA_WEIGHT, link->l_weight); + + if (link->ce_mask & LINK_ATTR_IFNAME) + NLA_PUT_STRING(msg, IFLA_IFNAME, link->l_name); + + if (link->ce_mask & LINK_ATTR_OPERSTATE) + NLA_PUT_U8(msg, IFLA_OPERSTATE, link->l_operstate); + + if (link->ce_mask & LINK_ATTR_LINKMODE) + NLA_PUT_U8(msg, IFLA_LINKMODE, link->l_linkmode); + + if (link->ce_mask & LINK_ATTR_IFALIAS) + NLA_PUT_STRING(msg, IFLA_IFALIAS, link->l_ifalias); + + if (link->ce_mask & LINK_ATTR_LINK) + NLA_PUT_U32(msg, IFLA_LINK, link->l_link); + + if (link->ce_mask & LINK_ATTR_MASTER) + NLA_PUT_U32(msg, IFLA_MASTER, link->l_master); + + if ((link->ce_mask & LINK_ATTR_LINKINFO) && link->l_info_ops) { + struct nlattr *info; + + if (!(info = nla_nest_start(msg, IFLA_LINKINFO))) + goto nla_put_failure; + + NLA_PUT_STRING(msg, IFLA_INFO_KIND, link->l_info_ops->io_name); + + if (link->l_info_ops->io_put_attrs && + link->l_info_ops->io_put_attrs(msg, link) < 0) + goto nla_put_failure; + + nla_nest_end(msg, info); + } + + if (!(af_spec = nla_nest_start(msg, IFLA_AF_SPEC))) + goto nla_put_failure; + + if (do_foreach_af(link, af_fill, msg) < 0) + goto nla_put_failure; + + nla_nest_end(msg, af_spec); + + *result = msg; + return 0; + +nla_put_failure: + nlmsg_free(msg); + return -NLE_MSGSIZE; +} + +/** + * @name Add / Modify + * @{ + */ + +/** + * Build a netlink message requesting the addition of new virtual link + * @arg link new link to add + * @arg flags additional netlink message flags + * @arg result pointer to store resulting netlink message + * + * The behaviour of this function is identical to rtnl_link_add() with + * the exception that it will not send the message but return it in the + * provided return pointer instead. + * + * @see rtnl_link_add() + * + * @note This operation is not supported on all kernel versions. + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_build_add_request(struct rtnl_link *link, int flags, + struct nl_msg **result) +{ + struct ifinfomsg ifi = { + .ifi_family = link->l_family, + .ifi_index = link->l_index, + .ifi_flags = link->l_flags, + }; + + return build_link_msg(RTM_NEWLINK, &ifi, link, flags, result); +} + +/** + * Add virtual link + * @arg sk netlink socket. + * @arg link new link to add + * @arg flags additional netlink message flags + * + * Builds a \c RTM_NEWLINK netlink message requesting the addition of + * a new virtual link. + * + * After sending, the function will wait for the ACK or an eventual + * error message to be received and will therefore block until the + * operation has been completed. + * + * @copydoc auto_ack_warning + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_add(struct nl_sock *sk, struct rtnl_link *link, int flags) +{ + struct nl_msg *msg; + int err; + + err = rtnl_link_build_add_request(link, flags, &msg); + if (err < 0) + return err; + + return nl_send_sync(sk, msg); +} + +/** + * Build a netlink message requesting the modification of link + * @arg orig original link to change + * @arg changes link containing the changes to be made + * @arg flags additional netlink message flags + * @arg result pointer to store resulting netlink message + * + * The behaviour of this function is identical to rtnl_link_change() with + * the exception that it will not send the message but return it in the + * provided return pointer instead. + * + * @see rtnl_link_change() + * + * @note The resulting message will have message type set to RTM_NEWLINK + * which may not work with older kernels. You may have to modify it + * to RTM_SETLINK (does not allow changing link info attributes) to + * have the change request work with older kernels. + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_build_change_request(struct rtnl_link *orig, + struct rtnl_link *changes, int flags, + struct nl_msg **result) +{ + struct ifinfomsg ifi = { + .ifi_family = orig->l_family, + .ifi_index = orig->l_index, + }; + int err; + + if (changes->ce_mask & LINK_ATTR_FLAGS) { + ifi.ifi_flags = orig->l_flags & ~changes->l_flag_mask; + ifi.ifi_flags |= changes->l_flags; + } + + if (changes->l_family && changes->l_family != orig->l_family) { + APPBUG("link change: family is immutable"); + return -NLE_IMMUTABLE; + } + + /* Avoid unnecessary name change requests */ + if (orig->ce_mask & LINK_ATTR_IFINDEX && + orig->ce_mask & LINK_ATTR_IFNAME && + changes->ce_mask & LINK_ATTR_IFNAME && + !strcmp(orig->l_name, changes->l_name)) + changes->ce_mask &= ~LINK_ATTR_IFNAME; + + if ((err = build_link_msg(RTM_NEWLINK, &ifi, changes, flags, result)) < 0) + goto errout; + + return 0; + +errout: + return err; +} + +/** + * Change link + * @arg sk netlink socket. + * @arg orig original link to be changed + * @arg changes link containing the changes to be made + * @arg flags additional netlink message flags + * + * Builds a \c RTM_NEWLINK netlink message requesting the change of + * a network link. If -EOPNOTSUPP is returned by the kernel, the + * message type will be changed to \c RTM_SETLINK and the message is + * resent to work around older kernel versions. + * + * The link to be changed is looked up based on the interface index + * supplied in the \p orig link. Optionaly the link name is used but + * only if no interface index is provided, otherwise providing an + * link name will result in the link name being changed. + * + * If no matching link exists, the function will return + * -NLE_OBJ_NOTFOUND. + * + * After sending, the function will wait for the ACK or an eventual + * error message to be received and will therefore block until the + * operation has been completed. + * + * @copydoc auto_ack_warning + * + * @note The link name can only be changed if the link has been put + * in opertional down state. (~IF_UP) + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *orig, + struct rtnl_link *changes, int flags) +{ + struct nl_msg *msg; + int err; + + err = rtnl_link_build_change_request(orig, changes, flags, &msg); + if (err < 0) + return err; + +retry: + err = nl_send_auto_complete(sk, msg); + if (err < 0) + goto errout; + + err = wait_for_ack(sk); + if (err == -NLE_OPNOTSUPP && msg->nm_nlh->nlmsg_type == RTM_NEWLINK) { + msg->nm_nlh->nlmsg_type = RTM_SETLINK; + goto retry; + } + +errout: + nlmsg_free(msg); + return err; +} + +/** @} */ + +/** + * @name Delete + * @{ + */ + +/** + * Build a netlink message requesting the deletion of a link + * @arg link Link to delete + * @arg result Pointer to store resulting netlink message + * + * The behaviour of this function is identical to rtnl_link_delete() with + * the exception that it will not send the message but return it in the + * provided return pointer instead. + * + * @see rtnl_link_delete() + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_build_delete_request(const struct rtnl_link *link, + struct nl_msg **result) +{ + struct nl_msg *msg; + struct ifinfomsg ifi = { + .ifi_index = link->l_index, + }; + + if (!(link->ce_mask & (LINK_ATTR_IFINDEX | LINK_ATTR_IFNAME))) { + APPBUG("ifindex or name must be specified"); + return -NLE_MISSING_ATTR; + } + + if (!(msg = nlmsg_alloc_simple(RTM_DELLINK, 0))) + return -NLE_NOMEM; + + if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + if (link->ce_mask & LINK_ATTR_IFNAME) + NLA_PUT_STRING(msg, IFLA_IFNAME, link->l_name); + + *result = msg; + return 0; + +nla_put_failure: + nlmsg_free(msg); + return -NLE_MSGSIZE; +} + +/** + * Delete link + * @arg sk Netlink socket + * @arg link Link to delete + * + * Builds a \c RTM_DELLINK netlink message requesting the deletion of + * a network link which has been previously added to the kernel and + * sends the message to the kernel. + * + * If no matching link exists, the function will return + * -NLE_OBJ_NOTFOUND. + * + * After sending, the function will wait for the ACK or an eventual + * error message to be received and will therefore block until the + * operation has been completed. + * + * @copydoc auto_ack_warning + * + * @note Only virtual links such as dummy interface or vlan interfaces + * can be deleted. It is not possible to delete physical interfaces + * such as ethernet interfaces or the loopback device. + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_delete(struct nl_sock *sk, const struct rtnl_link *link) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_link_build_delete_request(link, &msg)) < 0) + return err; + + return nl_send_sync(sk, msg); +} + +/** @} */ + +/** + * @name Link Object + * @{ + */ + +/** + * Allocate link object + * + * @see rtnl_link_put() + * @return New link object or NULL if allocation failed + */ +struct rtnl_link *rtnl_link_alloc(void) +{ + return (struct rtnl_link *) nl_object_alloc(&link_obj_ops); +} + +/** + * Return a link object reference + * + * @copydetails nl_object_put() + */ +void rtnl_link_put(struct rtnl_link *link) +{ + nl_object_put((struct nl_object *) link); +} + +/** + * Set name of link object + * @arg link Link object + * @arg name New name + * + * @note To change the name of a link in the kernel, set the interface + * index to the link you wish to change, modify the link name using + * this function and pass the link object to rtnl_link_change() or + * rtnl_link_add(). + * + * @route_doc{link_attr_name, Link Name} + * @see rtnl_link_get_name() + * @see rtnl_link_set_ifindex() + */ +void rtnl_link_set_name(struct rtnl_link *link, const char *name) +{ + strncpy(link->l_name, name, sizeof(link->l_name) - 1); + link->ce_mask |= LINK_ATTR_IFNAME; +} + +/** + * Return name of link object + * @arg link Link object + * + * @route_doc{link_attr_name, Link Name} + * @see rtnl_link_set_name() + * @return Link name or NULL if name is not specified + */ +char *rtnl_link_get_name(struct rtnl_link *link) +{ + return link->ce_mask & LINK_ATTR_IFNAME ? link->l_name : NULL; +} + +static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos, + struct nl_addr *new, int flag) +{ + if (*pos) + nl_addr_put(*pos); + + nl_addr_get(new); + *pos = new; + + link->ce_mask |= flag; +} + +/** + * Set link layer address of link object + * @arg link Link object + * @arg addr New link layer address + * + * The function increments the reference counter of the address object + * and overwrites any existing link layer address previously assigned. + * + * @route_doc{link_attr_address, Link layer address} + * @see rtnl_link_get_addr() + */ +void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr) +{ + __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR); +} + +/** + * Return link layer address of link object + * @arg link Link object + * + * @copydoc pointer_lifetime_warning + * @route_doc{link_attr_address, Link Layer Address} + * @see rtnl_link_set_addr() + * @return Link layer address or NULL if not set. + */ +struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link) +{ + return link->ce_mask & LINK_ATTR_ADDR ? link->l_addr : NULL; +} + +/** + * Set link layer broadcast address of link object + * @arg link Link object + * @arg addr New broadcast address + * + * The function increments the reference counter of the address object + * and overwrites any existing link layer broadcast address previously + * assigned. + * + * @route_doc{link_attr_broadcast, Link Layer Broadcast Address} + * @see rtnl_link_get_broadcast() + */ +void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *addr) +{ + __assign_addr(link, &link->l_bcast, addr, LINK_ATTR_BRD); +} + +/** + * Return link layer broadcast address of link object + * @arg link Link object + * + * @copydoc pointer_lifetime_warning + * @route_doc{link_attr_address, Link Layer Address} + * @see rtnl_link_set_broadcast() + * @return Link layer address or NULL if not set. + */ +struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link) +{ + return link->ce_mask & LINK_ATTR_BRD ? link->l_bcast : NULL; +} + +/** + * Set flags of link object + * @arg link Link object + * @arg flags Flags + * + * @see rtnl_link_get_flags() + * @see rtnl_link_unset_flags() + */ +void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags) +{ + link->l_flag_mask |= flags; + link->l_flags |= flags; + link->ce_mask |= LINK_ATTR_FLAGS; +} + +/** + * Unset flags of link object + * @arg link Link object + * @arg flags Flags + * + * @see rtnl_link_set_flags() + * @see rtnl_link_get_flags() + */ +void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags) +{ + link->l_flag_mask |= flags; + link->l_flags &= ~flags; + link->ce_mask |= LINK_ATTR_FLAGS; +} + +/** + * Return flags of link object + * @arg link Link object + * + * @route_doc{link_attr_flags, Link Flags} + * @see rtnl_link_set_flags() + * @see rtnl_link_unset_flags() + * @return Link flags or 0 if none have been set. + */ +unsigned int rtnl_link_get_flags(struct rtnl_link *link) +{ + return link->l_flags; +} + +/** + * Set address family of link object + * + * @see rtnl_link_get_family() + */ +void rtnl_link_set_family(struct rtnl_link *link, int family) +{ + link->l_family = family; + link->ce_mask |= LINK_ATTR_FAMILY; +} + +/** + * Return address family of link object + * @arg link Link object + * + * @see rtnl_link_set_family() + * @return Address family or \c AF_UNSPEC if not specified. + */ +int rtnl_link_get_family(struct rtnl_link *link) +{ + return link->ce_mask & LINK_ATTR_FAMILY ? link->l_family : AF_UNSPEC; +} + +/** + * Set hardware type of link object + * @arg link Link object + * @arg arptype New hardware type \c (ARPHRD_*) + * + * @route_doc{link_attr_arptype, Hardware Type} + * @copydoc read_only_attribute + * @see rtnl_link_get_arptype() + */ +void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype) +{ + link->l_arptype = arptype; + link->ce_mask |= LINK_ATTR_ARPTYPE; +} + +/** + * Get hardware type of link object + * @arg link Link object + * + * @route_doc{link_attr_arptype, Hardware Type} + * @see rtnl_link_set_arptype() + * @return Hardware type \c (ARPHRD_ETHER *) or \c ARPHRD_VOID + */ +unsigned int rtnl_link_get_arptype(struct rtnl_link *link) +{ + if (link->ce_mask & LINK_ATTR_ARPTYPE) + return link->l_arptype; + else + return ARPHRD_VOID; +} + +/** + * Set interface index of link object + * @arg link Link object + * @arg ifindex Interface index + * + * @route_doc{link_attr_ifindex, Interface Index} + * @see rtnl_link_get_ifindex() + */ +void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex) +{ + link->l_index = ifindex; + link->ce_mask |= LINK_ATTR_IFINDEX; +} + + +/** + * Return interface index of link object + * @arg link Link object + * + * @route_doc{link_attr_ifindex, Interface Index} + * @see rtnl_link_set_ifindex() + * @return Interface index or 0 if not set. + */ +int rtnl_link_get_ifindex(struct rtnl_link *link) +{ + return link->l_index; +} + +/** + * Set Maximum Transmission Unit of link object + * @arg link Link object + * @arg mtu New MTU value in number of bytes + * + * @route_doc{link_attr_mtu, Maximum Transmission Unit} + * @see rtnl_link_get_mtu() + */ +void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu) +{ + link->l_mtu = mtu; + link->ce_mask |= LINK_ATTR_MTU; +} + +/** + * Return maximum transmission unit of link object + * @arg link Link object + * + * @route_doc{link_attr_mtu, Maximum Transmission Unit} + * @see rtnl_link_set_mtu() + * @return MTU in bytes or 0 if not set + */ +unsigned int rtnl_link_get_mtu(struct rtnl_link *link) +{ + return link->l_mtu; +} + +/** + * Set transmission queue length + * @arg link Link object + * @arg txqlen New queue length + * + * The unit is dependant on the link type. The most common units is number + * of packets. + * + * @route_doc{link_attr_txqlen, Transmission Queue Length} + */ +void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen) +{ + link->l_txqlen = txqlen; + link->ce_mask |= LINK_ATTR_TXQLEN; +} + +/** + * Return transmission queue length + * @arg link Link object + * + * The unit is dependant on the link type. The most common units is number + * of packets. + * + * @route_doc{link_attr_txqlen, Transmission Queue Length} + * @return queue length or 0 if not specified. + */ +unsigned int rtnl_link_get_txqlen(struct rtnl_link *link) +{ + return link->ce_mask & LINK_ATTR_TXQLEN ? link->l_txqlen : 0; +} + +void rtnl_link_set_link(struct rtnl_link *link, int ifindex) +{ + link->l_link = ifindex; + link->ce_mask |= LINK_ATTR_LINK; +} + +int rtnl_link_get_link(struct rtnl_link *link) +{ + return link->l_link; +} + +/** + * Set master link of link object + * @arg link Link object + * @arg ifindex Interface index of master link + * + * @see rtnl_link_get_master() + */ +void rtnl_link_set_master(struct rtnl_link *link, int ifindex) +{ + link->l_master = ifindex; + link->ce_mask |= LINK_ATTR_MASTER; +} + +/** + * Return master link of link object + * @arg link Link object + * + * @see rtnl_link_set_master() + * @return Interface index of master link or 0 if not specified + */ +int rtnl_link_get_master(struct rtnl_link *link) +{ + return link->l_master; +} + +/** + * Set operational status of link object + * @arg link Link object + * @arg status New opertional status + * + * @route_doc{link_attr_operstate, Operational Status}} + * @see rtnl_link_get_operstate() + */ +void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t status) +{ + link->l_operstate = status; + link->ce_mask |= LINK_ATTR_OPERSTATE; +} + +/** + * Return operational status of link object + * @arg link Link object + * + * @route_doc{link_attr_operstate, Operational Status} + * @see rtnl_link_set_operstate() + * @return Opertional state or \c IF_OPER_UNKNOWN + */ +uint8_t rtnl_link_get_operstate(struct rtnl_link *link) +{ + return link->l_operstate; +} + +/** + * Set link mode of link object + * @arg link Link object + * @arg mode New link mode + * + * @route_doc{link_attr_mode, Mode} + * @see rtnl_link_get_linkmode() + */ +void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t mode) +{ + link->l_linkmode = mode; + link->ce_mask |= LINK_ATTR_LINKMODE; +} + +/** + * Return link mode of link object + * @arg link Link object + * + * @route_doc{link_attr_mode, Mode} + * @see rtnl_link_get_linkmode() + * @return Link mode or \c IF_LINK_MODE_DEFAULT + */ +uint8_t rtnl_link_get_linkmode(struct rtnl_link *link) +{ + return link->l_linkmode; +} + +/** + * Return alias name of link object (SNMP IfAlias) + * @arg link Link object + * + * @route_doc{link_attr_alias, Alias} + * @see rtnl_link_set_ifalias() + * @return Alias name or NULL if not set. + */ +const char *rtnl_link_get_ifalias(struct rtnl_link *link) +{ + return link->l_ifalias; +} + +/** + * Set alias name of link object (SNMP IfAlias) + * @arg link Link object + * @arg alias Alias name or NULL to unset + * + * Sets the alias name of the link to the specified name. The alias + * name can be unset by specyfing NULL as the alias. The name will + * be strdup()ed, so no need to provide a persistent character string. + * + * @route_doc{link_attr_alias, Alias} + * @see rtnl_link_get_ifalias() + */ +void rtnl_link_set_ifalias(struct rtnl_link *link, const char *alias) +{ + free(link->l_ifalias); + link->ce_mask &= ~LINK_ATTR_IFALIAS; + + if (alias) { + link->l_ifalias = strdup(alias); + link->ce_mask |= LINK_ATTR_IFALIAS; + } +} + +/** + * Set queueing discipline name of link object + * @arg link Link object + * @arg name Name of queueing discipline + * + * @copydoc read_only_attribute + * + * For more information on how to modify the qdisc of a link, see section + * @ref_route{route_tc, Traffic Control}. + * + * @route_doc{link_attr_qdisc, Queueing Discipline Name} + * @see rtnl_link_get_qdisc() + */ +void rtnl_link_set_qdisc(struct rtnl_link *link, const char *name) +{ + strncpy(link->l_qdisc, name, sizeof(link->l_qdisc) - 1); + link->ce_mask |= LINK_ATTR_QDISC; +} + +/** + * Return name of queueing discipline of link object + * @arg link Link object + * + * @route_doc{link_attr_qdisc, Queueing Discipline Name} + * @see rtnl_link_set_qdisc() + * @return Name of qdisc or NULL if not specified. + */ +char *rtnl_link_get_qdisc(struct rtnl_link *link) +{ + return link->ce_mask & LINK_ATTR_QDISC ? link->l_qdisc : NULL; +} + + +/** + * Return number of PCI virtual functions of link object + * @arg link Link object + * @arg num_vf Pointer to store number of VFs + * + * @return 0 on success or -NLE_OPNOTSUPP if not available + */ +int rtnl_link_get_num_vf(struct rtnl_link *link, uint32_t *num_vf) +{ + if (link->ce_mask & LINK_ATTR_NUM_VF) { + *num_vf = link->l_num_vf; + return 0; + } else + return -NLE_OPNOTSUPP; +} + +/** + * Return value of link statistics counter + * @arg link Link object + * @arg id Identifier of statistical counter + * + * @return Value of counter or 0 if not specified. + */ +uint64_t rtnl_link_get_stat(struct rtnl_link *link, rtnl_link_stat_id_t id) +{ + if (id > RTNL_LINK_STATS_MAX) + return 0; + + return link->l_stats[id]; +} + +/** + * Set value of link statistics counter + * @arg link Link object + * @arg id Identifier of statistical counter + * @arg value New value + * + * \note Changing the value of a statistical counter will not change the + * value in the kernel. + * + * @return 0 on success or a negative error code + */ +int rtnl_link_set_stat(struct rtnl_link *link, rtnl_link_stat_id_t id, + const uint64_t value) +{ + if (id > RTNL_LINK_STATS_MAX) + return -NLE_INVAL; + + link->l_stats[id] = value; + + return 0; +} + +/** + * Set type of link object + * @arg link Link object + * @arg type Name of link type + * + * Looks up the link type module and prepares the link to store type + * specific attributes. If a type has been assigned already it will + * be released with all link type specific attributes lost. + * + * @route_doc{link_modules, Link Modules} + * @return 0 on success or a negative errror code. + */ +int rtnl_link_set_type(struct rtnl_link *link, const char *type) +{ + struct rtnl_link_info_ops *io; + int err; + + if ((io = rtnl_link_info_ops_lookup(type)) == NULL) + return -NLE_OPNOTSUPP; + + if (link->l_info_ops) + release_link_info(link); + + if (io->io_alloc && (err = io->io_alloc(link)) < 0) + return err; + + link->ce_mask |= LINK_ATTR_LINKINFO; + link->l_info_ops = io; + + return 0; +} + +/** + * Return type of link + * @arg link Link object + * + * @route_doc{link_modules, Link Modules} + * @return Name of link type or NULL if not specified. + */ +char *rtnl_link_get_type(struct rtnl_link *link) +{ + return link->l_info_ops ? link->l_info_ops->io_name : NULL; +} + +/** @} */ + +/** + * @name Master/Slave + * @{ + */ + +/** + * Enslave slave link to master link + * @arg sock netlink socket + * @arg master ifindex of master link + * @arg slave ifindex of slave link + * + * This function is identical to rtnl_link_enslave() except that + * it takes interface indices instead of rtnl_link objects. + * + * @see rtnl_link_enslave() + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_enslave_ifindex(struct nl_sock *sock, int master, int slave) +{ + struct rtnl_link *link; + int err; + + if (!(link = rtnl_link_alloc())) + return -NLE_NOMEM; + + rtnl_link_set_ifindex(link, slave); + rtnl_link_set_master(link, master); + + if ((err = rtnl_link_change(sock, link, link, 0)) < 0) + goto errout; + + rtnl_link_put(link); + + /* + * Due to the kernel not signaling whether this opertion is + * supported or not, we will retrieve the attribute to see if the + * request was successful. If the master assigned remains unchanged + * we will return NLE_OPNOTSUPP to allow performing backwards + * compatibility of some sort. + */ + if ((err = rtnl_link_get_kernel(sock, slave, NULL, &link)) < 0) + return err; + + if (rtnl_link_get_master(link) != master) + err = -NLE_OPNOTSUPP; + +errout: + rtnl_link_put(link); + + return err; +} + +/** + * Enslave slave link to master link + * @arg sock netlink socket + * @arg master master link + * @arg slave slave link + * + * Constructs a RTM_NEWLINK or RTM_SETLINK message adding the slave to + * the master and sends the request via the specified netlink socket. + * + * @note The feature of enslaving/releasing via netlink has only been added + * recently to the kernel (Feb 2011). Also, the kernel does not signal + * if the operation is not supported. Therefore this function will + * verify if the master assignment has changed and will return + * -NLE_OPNOTSUPP if it did not. + * + * @see rtnl_link_enslave_ifindex() + * @see rtnl_link_release() + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_enslave(struct nl_sock *sock, struct rtnl_link *master, + struct rtnl_link *slave) +{ + return rtnl_link_enslave_ifindex(sock, rtnl_link_get_ifindex(master), + rtnl_link_get_ifindex(slave)); +} + +/** + * Release slave link from its master + * @arg sock netlink socket + * @arg slave slave link + * + * This function is identical to rtnl_link_release() except that + * it takes an interface index instead of a rtnl_link object. + * + * @see rtnl_link_release() + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_release_ifindex(struct nl_sock *sock, int slave) +{ + return rtnl_link_enslave_ifindex(sock, 0, slave); +} + +/** + * Release slave link from its master + * @arg sock netlink socket + * @arg slave slave link + * + * Constructs a RTM_NEWLINK or RTM_SETLINK message releasing the slave from + * its master and sends the request via the specified netlink socket. + * + * @note The feature of enslaving/releasing via netlink has only been added + * recently to the kernel (Feb 2011). Also, the kernel does not signal + * if the operation is not supported. Therefore this function will + * verify if the master assignment has changed and will return + * -NLE_OPNOTSUPP if it did not. + * + * @see rtnl_link_release_ifindex() + * @see rtnl_link_enslave() + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_release(struct nl_sock *sock, struct rtnl_link *slave) +{ + return rtnl_link_release_ifindex(sock, rtnl_link_get_ifindex(slave)); +} + +/** @} */ + +/** + * @name Utilities + * @{ + */ + +static const struct trans_tbl link_flags[] = { + __ADD(IFF_LOOPBACK, loopback) + __ADD(IFF_BROADCAST, broadcast) + __ADD(IFF_POINTOPOINT, pointopoint) + __ADD(IFF_MULTICAST, multicast) + __ADD(IFF_NOARP, noarp) + __ADD(IFF_ALLMULTI, allmulti) + __ADD(IFF_PROMISC, promisc) + __ADD(IFF_MASTER, master) + __ADD(IFF_SLAVE, slave) + __ADD(IFF_DEBUG, debug) + __ADD(IFF_DYNAMIC, dynamic) + __ADD(IFF_AUTOMEDIA, automedia) + __ADD(IFF_PORTSEL, portsel) + __ADD(IFF_NOTRAILERS, notrailers) + __ADD(IFF_UP, up) + __ADD(IFF_RUNNING, running) + __ADD(IFF_LOWER_UP, lowerup) + __ADD(IFF_DORMANT, dormant) + __ADD(IFF_ECHO, echo) +}; + +char *rtnl_link_flags2str(int flags, char *buf, size_t len) +{ + return __flags2str(flags, buf, len, link_flags, + ARRAY_SIZE(link_flags)); +} + +int rtnl_link_str2flags(const char *name) +{ + return __str2flags(name, link_flags, ARRAY_SIZE(link_flags)); +} + +static const struct trans_tbl link_stats[] = { + __ADD(RTNL_LINK_RX_PACKETS, rx_packets) + __ADD(RTNL_LINK_TX_PACKETS, tx_packets) + __ADD(RTNL_LINK_RX_BYTES, rx_bytes) + __ADD(RTNL_LINK_TX_BYTES, tx_bytes) + __ADD(RTNL_LINK_RX_ERRORS, rx_errors) + __ADD(RTNL_LINK_TX_ERRORS, tx_errors) + __ADD(RTNL_LINK_RX_DROPPED, rx_dropped) + __ADD(RTNL_LINK_TX_DROPPED, tx_dropped) + __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed) + __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed) + __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err) + __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err) + __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err) + __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err) + __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err) + __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err) + __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err) + __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err) + __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err) + __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err) + __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err) + __ADD(RTNL_LINK_COLLISIONS, collisions) + __ADD(RTNL_LINK_MULTICAST, multicast) + __ADD(RTNL_LINK_IP6_INPKTS, Ip6InReceives) + __ADD(RTNL_LINK_IP6_INHDRERRORS, Ip6InHdrErrors) + __ADD(RTNL_LINK_IP6_INTOOBIGERRORS, Ip6InTooBigErrors) + __ADD(RTNL_LINK_IP6_INNOROUTES, Ip6InNoRoutes) + __ADD(RTNL_LINK_IP6_INADDRERRORS, Ip6InAddrErrors) + __ADD(RTNL_LINK_IP6_INUNKNOWNPROTOS, Ip6InUnknownProtos) + __ADD(RTNL_LINK_IP6_INTRUNCATEDPKTS, Ip6InTruncatedPkts) + __ADD(RTNL_LINK_IP6_INDISCARDS, Ip6InDiscards) + __ADD(RTNL_LINK_IP6_INDELIVERS, Ip6InDelivers) + __ADD(RTNL_LINK_IP6_OUTFORWDATAGRAMS, Ip6OutForwDatagrams) + __ADD(RTNL_LINK_IP6_OUTPKTS, Ip6OutRequests) + __ADD(RTNL_LINK_IP6_OUTDISCARDS, Ip6OutDiscards) + __ADD(RTNL_LINK_IP6_OUTNOROUTES, Ip6OutNoRoutes) + __ADD(RTNL_LINK_IP6_REASMTIMEOUT, Ip6ReasmTimeout) + __ADD(RTNL_LINK_IP6_REASMREQDS, Ip6ReasmReqds) + __ADD(RTNL_LINK_IP6_REASMOKS, Ip6ReasmOKs) + __ADD(RTNL_LINK_IP6_REASMFAILS, Ip6ReasmFails) + __ADD(RTNL_LINK_IP6_FRAGOKS, Ip6FragOKs) + __ADD(RTNL_LINK_IP6_FRAGFAILS, Ip6FragFails) + __ADD(RTNL_LINK_IP6_FRAGCREATES, Ip6FragCreates) + __ADD(RTNL_LINK_IP6_INMCASTPKTS, Ip6InMcastPkts) + __ADD(RTNL_LINK_IP6_OUTMCASTPKTS, Ip6OutMcastPkts) + __ADD(RTNL_LINK_IP6_INBCASTPKTS, Ip6InBcastPkts) + __ADD(RTNL_LINK_IP6_OUTBCASTPKTS, Ip6OutBcastPkts) + __ADD(RTNL_LINK_IP6_INOCTETS, Ip6InOctets) + __ADD(RTNL_LINK_IP6_OUTOCTETS, Ip6OutOctets) + __ADD(RTNL_LINK_IP6_INMCASTOCTETS, Ip6InMcastOctets) + __ADD(RTNL_LINK_IP6_OUTMCASTOCTETS, Ip6OutMcastOctets) + __ADD(RTNL_LINK_IP6_INBCASTOCTETS, Ip6InBcastOctets) + __ADD(RTNL_LINK_IP6_OUTBCASTOCTETS, Ip6OutBcastOctets) + __ADD(RTNL_LINK_ICMP6_INMSGS, ICMP6_InMsgs) + __ADD(RTNL_LINK_ICMP6_INERRORS, ICMP6_InErrors) + __ADD(RTNL_LINK_ICMP6_OUTMSGS, ICMP6_OutMsgs) + __ADD(RTNL_LINK_ICMP6_OUTERRORS, ICMP6_OutErrors) +}; + +char *rtnl_link_stat2str(int st, char *buf, size_t len) +{ + return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats)); +} + +int rtnl_link_str2stat(const char *name) +{ + return __str2type(name, link_stats, ARRAY_SIZE(link_stats)); +} + +static const struct trans_tbl link_operstates[] = { + __ADD(IF_OPER_UNKNOWN, unknown) + __ADD(IF_OPER_NOTPRESENT, notpresent) + __ADD(IF_OPER_DOWN, down) + __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown) + __ADD(IF_OPER_TESTING, testing) + __ADD(IF_OPER_DORMANT, dormant) + __ADD(IF_OPER_UP, up) +}; + +char *rtnl_link_operstate2str(uint8_t st, char *buf, size_t len) +{ + return __type2str(st, buf, len, link_operstates, + ARRAY_SIZE(link_operstates)); +} + +int rtnl_link_str2operstate(const char *name) +{ + return __str2type(name, link_operstates, + ARRAY_SIZE(link_operstates)); +} + +static const struct trans_tbl link_modes[] = { + __ADD(IF_LINK_MODE_DEFAULT, default) + __ADD(IF_LINK_MODE_DORMANT, dormant) +}; + +char *rtnl_link_mode2str(uint8_t st, char *buf, size_t len) +{ + return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes)); +} + +int rtnl_link_str2mode(const char *name) +{ + return __str2type(name, link_modes, ARRAY_SIZE(link_modes)); +} + +/** @} */ + +/** + * @name Deprecated Functions + */ + +/** + * @deprecated Use of this function is deprecated, use rtnl_link_set_type() + */ +int rtnl_link_set_info_type(struct rtnl_link *link, const char *type) +{ + return rtnl_link_set_type(link, type); +} + +/** + * @deprecated Use of this function is deprecated, use rtnl_link_get_type() + */ +char *rtnl_link_get_info_type(struct rtnl_link *link) +{ + return rtnl_link_get_type(link); +} + +/** + * @deprecated The weight attribute is unused and obsoleted in all recent kernels + */ +void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight) +{ + link->l_weight = weight; + link->ce_mask |= LINK_ATTR_WEIGHT; +} + +/** + * @deprecated The weight attribute is unused and obsoleted in all recent kernels + */ +unsigned int rtnl_link_get_weight(struct rtnl_link *link) +{ + return link->l_weight; +} + +/** @} */ + +static struct nl_object_ops link_obj_ops = { + .oo_name = "route/link", + .oo_size = sizeof(struct rtnl_link), + .oo_free_data = link_free_data, + .oo_clone = link_clone, + .oo_dump = { + [NL_DUMP_LINE] = link_dump_line, + [NL_DUMP_DETAILS] = link_dump_details, + [NL_DUMP_STATS] = link_dump_stats, + }, + .oo_compare = link_compare, + .oo_attrs2str = link_attrs2str, + .oo_id_attrs = LINK_ATTR_IFINDEX, +}; + +static struct nl_af_group link_groups[] = { + { AF_UNSPEC, RTNLGRP_LINK }, + { END_OF_GROUP_LIST }, +}; + +static struct nl_cache_ops rtnl_link_ops = { + .co_name = "route/link", + .co_hdrsize = sizeof(struct ifinfomsg), + .co_msgtypes = { + { RTM_NEWLINK, NL_ACT_NEW, "new" }, + { RTM_DELLINK, NL_ACT_DEL, "del" }, + { RTM_GETLINK, NL_ACT_GET, "get" }, + { RTM_SETLINK, NL_ACT_CHANGE, "set" }, + END_OF_MSGTYPES_LIST, + }, + .co_protocol = NETLINK_ROUTE, + .co_groups = link_groups, + .co_request_update = link_request_update, + .co_msg_parser = link_msg_parser, + .co_event_filter = link_event_filter, + .co_obj_ops = &link_obj_ops, +}; + +static void __init link_init(void) +{ + nl_cache_mngt_register(&rtnl_link_ops); +} + +static void __exit link_exit(void) +{ + nl_cache_mngt_unregister(&rtnl_link_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/link/.dirstamp b/libnetwork/libnl3/lib/route/link/.dirstamp new file mode 100644 index 0000000..e69de29 diff --git a/libnetwork/libnl3/lib/route/link/api.c b/libnetwork/libnl3/lib/route/link/api.c new file mode 100644 index 0000000..f7907a7 --- /dev/null +++ b/libnetwork/libnl3/lib/route/link/api.c @@ -0,0 +1,316 @@ +/* + * lib/route/link/api.c Link Info API + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup link + * @defgroup link_API Link Modules API + * @brief API for modules implementing specific link types/semantics. + * + * @par 1) Registering/Unregistering a new link info type + * @code + * static struct rtnl_link_info_ops vlan_info_ops = { + * .io_name = "vlan", + * .io_alloc = vlan_alloc, + * .io_parse = vlan_parse, + * .io_dump[NL_DUMP_BRIEF] = vlan_dump_brief, + * .io_dump[NL_DUMP_FULL] = vlan_dump_full, + * .io_free = vlan_free, + * }; + * + * static void __init vlan_init(void) + * { + * rtnl_link_register_info(&vlan_info_ops); + * } + * + * static void __exit vlan_exit(void) + * { + * rtnl_link_unregister_info(&vlan_info_ops); + * } + * @endcode + * + * @{ + */ + +#include +#include +#include +#include +#include + +static NL_LIST_HEAD(info_ops); + +static struct rtnl_link_info_ops *__rtnl_link_info_ops_lookup(const char *name) +{ + struct rtnl_link_info_ops *ops; + + nl_list_for_each_entry(ops, &info_ops, io_list) + if (!strcmp(ops->io_name, name)) + return ops; + + return NULL; +} + +/** + * @name Link Info Modules + * @{ + */ + +/** + * Return operations of a specific link info type + * @arg name Name of link info type. + * + * @note The returned pointer must be given back using rtnl_link_info_ops_put() + * + * @return Pointer to operations or NULL if unavailable. + */ +struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *name) +{ + struct rtnl_link_info_ops *ops; + + if ((ops = __rtnl_link_info_ops_lookup(name))) + ops->io_refcnt++; + + return ops; +} + +/** + * Give back reference to a set of operations. + * @arg ops Link info operations. + */ +void rtnl_link_info_ops_put(struct rtnl_link_info_ops *ops) +{ + if (ops) + ops->io_refcnt--; +} + +/** + * Register operations for a link info type + * @arg ops Link info operations + * + * This function must be called by modules implementing a specific link + * info type. It will make the operations implemented by the module + * available for everyone else. + * + * @return 0 on success or a negative error code. + * @return -NLE_INVAL Link info name not specified. + * @return -NLE_EXIST Operations for address family already registered. + */ +int rtnl_link_register_info(struct rtnl_link_info_ops *ops) +{ + if (ops->io_name == NULL) + return -NLE_INVAL; + + if (__rtnl_link_info_ops_lookup(ops->io_name)) + return -NLE_EXIST; + + NL_DBG(1, "Registered link info operations %s\n", ops->io_name); + + nl_list_add_tail(&ops->io_list, &info_ops); + + return 0; +} + +/** + * Unregister operations for a link info type + * @arg ops Link info operations + * + * This function must be called if a module implementing a specific link + * info type is unloaded or becomes unavailable. It must provide a + * set of operations which have previously been registered using + * rtnl_link_register_info(). + * + * @return 0 on success or a negative error code + * @return _NLE_OPNOTSUPP Link info operations not registered. + * @return -NLE_BUSY Link info operations still in use. + */ +int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops) +{ + struct rtnl_link_info_ops *t; + + nl_list_for_each_entry(t, &info_ops, io_list) { + if (t == ops) { + if (t->io_refcnt > 0) + return -NLE_BUSY; + + nl_list_del(&t->io_list); + + NL_DBG(1, "Unregistered link info operations %s\n", + ops->io_name); + + return 0; + } + } + + return -NLE_OPNOTSUPP; +} + +/** @} */ + +/** + * @name Link Address Family Modules + * @{ + */ + +static struct rtnl_link_af_ops *af_ops[AF_MAX]; + +/** + * Return operations of a specific link address family + * @arg family Address family + * + * @note The returned pointer must be given back using rtnl_link_af_ops_put() + * + * @return Pointer to operations or NULL if unavailable. + */ +struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(const unsigned int family) +{ + if (family == AF_UNSPEC || family >= AF_MAX) + return NULL; + + if (af_ops[family]) + af_ops[family]->ao_refcnt++; + + return af_ops[family]; +} + +/** + * Give back reference to a set of operations. + * @arg ops Address family operations. + */ +void rtnl_link_af_ops_put(struct rtnl_link_af_ops *ops) +{ + if (ops) + ops->ao_refcnt--; +} + +/** + * Allocate and return data buffer for link address family modules + * @arg link Link object + * @arg ops Address family operations + * + * This function must be called by link address family modules in all + * cases where the API does not provide the data buffer as argument + * already. This typically includes set functions the module provides. + * Calling this function is strictly required to ensure proper allocation + * of the buffer upon first use. Link objects will NOT proactively + * allocate a data buffer for each registered link address family. + * + * @return Pointer to data buffer or NULL on error. + */ +void *rtnl_link_af_alloc(struct rtnl_link *link, + const struct rtnl_link_af_ops *ops) +{ + int family; + + if (!link || !ops) + BUG(); + + family = ops->ao_family; + + if (!link->l_af_data[family]) { + if (!ops->ao_alloc) + BUG(); + + link->l_af_data[family] = ops->ao_alloc(link); + if (!link->l_af_data[family]) + return NULL; + } + + return link->l_af_data[family]; +} + +/** + * Return data buffer for link address family modules + * @arg link Link object + * @arg ops Address family operations + * + * This function returns a pointer to the data buffer for the specified link + * address family module or NULL if the buffer was not allocated yet. This + * function is typically used by get functions of modules which are not + * interested in having the data buffer allocated if no values have been set + * yet. + * + * @return Pointer to data buffer or NULL on error. + */ +void *rtnl_link_af_data(const struct rtnl_link *link, + const struct rtnl_link_af_ops *ops) +{ + if (!link || !ops) + BUG(); + + return link->l_af_data[ops->ao_family]; +} + +/** + * Register operations for a link address family + * @arg ops Address family operations + * + * This function must be called by modules implementing a specific link + * address family. It will make the operations implemented by the module + * available for everyone else. + * + * @return 0 on success or a negative error code. + * @return -NLE_INVAL Address family is out of range (0..AF_MAX) + * @return -NLE_EXIST Operations for address family already registered. + */ +int rtnl_link_af_register(struct rtnl_link_af_ops *ops) +{ + if (ops->ao_family == AF_UNSPEC || ops->ao_family >= AF_MAX) + return -NLE_INVAL; + + if (af_ops[ops->ao_family]) + return -NLE_EXIST; + + ops->ao_refcnt = 0; + af_ops[ops->ao_family] = ops; + + NL_DBG(1, "Registered link address family operations %u\n", + ops->ao_family); + + return 0; +} + +/** + * Unregister operations for a link address family + * @arg ops Address family operations + * + * This function must be called if a module implementing a specific link + * address family is unloaded or becomes unavailable. It must provide a + * set of operations which have previously been registered using + * rtnl_link_af_register(). + * + * @return 0 on success or a negative error code + * @return -NLE_INVAL ops is NULL + * @return -NLE_OBJ_NOTFOUND Address family operations not registered. + * @return -NLE_BUSY Address family operations still in use. + */ +int rtnl_link_af_unregister(struct rtnl_link_af_ops *ops) +{ + if (!ops) + return -NLE_INVAL; + + if (!af_ops[ops->ao_family]) + return -NLE_OBJ_NOTFOUND; + + if (ops->ao_refcnt > 0) + return -NLE_BUSY; + + af_ops[ops->ao_family] = NULL; + + NL_DBG(1, "Unregistered link address family operations %u\n", + ops->ao_family); + + return 0; +} + +/** @} */ + +/** @} */ + diff --git a/libnetwork/libnl3/lib/route/link/bonding.c b/libnetwork/libnl3/lib/route/link/bonding.c new file mode 100644 index 0000000..5788f69 --- /dev/null +++ b/libnetwork/libnl3/lib/route/link/bonding.c @@ -0,0 +1,217 @@ +/* + * lib/route/link/bonding.c Bonding Link Module + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2011 Thomas Graf + */ + +/** + * @ingroup link + * @defgroup bonding Bonding + * + * @details + * \b Link Type Name: "bond" + * + * @route_doc{link_bonding, Bonding Documentation} + * @{ + */ + +#include +#include +#include + +/** + * Create a new kernel bonding device + * @arg sock netlink socket + * @arg name name of bonding device or NULL + * @arg opts bonding options (currently unused) + * + * Creates a new bonding device in the kernel. If no name is + * provided, the kernel will automatically pick a name of the + * form "type%d" (e.g. bond0, vlan1, etc.) + * + * The \a opts argument is currently unused. In the future, it + * may be used to carry additional bonding options to be set + * when creating the bonding device. + * + * @note When letting the kernel assign a name, it will become + * difficult to retrieve the interface afterwards because + * you have to guess the name the kernel has chosen. It is + * therefore not recommended to not provide a device name. + * + * @see rtnl_link_bond_enslave() + * @see rtnl_link_bond_release() + * + * @return 0 on success or a negative error code + */ +int rtnl_link_bond_add(struct nl_sock *sock, const char *name, + struct rtnl_link *opts) +{ + struct rtnl_link *link; + int err; + + if (!(link = rtnl_link_alloc())) + return -NLE_NOMEM; + + if (!name) { + if (opts) + name = rtnl_link_get_name(opts); + + if (!name) + return -NLE_MISSING_ATTR; + } + + if ((err = rtnl_link_set_type(link, "bond")) < 0) + goto errout; + + + rtnl_link_set_name(link, name); + + err = rtnl_link_add(sock, link, NLM_F_CREATE); +errout: + rtnl_link_put(link); + + return err; +} + +/** + * Add a link to a bond (enslave) + * @arg sock netlink socket + * @arg master ifindex of bonding master + * @arg slave ifindex of slave link to add to bond + * + * This function is identical to rtnl_link_bond_enslave() except that + * it takes interface indices instead of rtnl_link objcets. + * + * @see rtnl_link_bond_enslave() + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_bond_enslave_ifindex(struct nl_sock *sock, int master, + int slave) +{ + struct rtnl_link *link; + int err; + + if (!(link = rtnl_link_alloc())) + return -NLE_NOMEM; + + if ((err = rtnl_link_set_type(link, "bond")) < 0) + goto errout; + + rtnl_link_set_ifindex(link, slave); + rtnl_link_set_master(link, master); + + if ((err = rtnl_link_change(sock, link, link, 0)) < 0) + goto errout; + + rtnl_link_put(link); + + /* + * Due to the kernel not signaling whether this opertion is + * supported or not, we will retrieve the attribute to see if the + * request was successful. If the master assigned remains unchanged + * we will return NLE_OPNOTSUPP to allow performing backwards + * compatibility of some sort. + */ + if ((err = rtnl_link_get_kernel(sock, slave, NULL, &link)) < 0) + return err; + + if (rtnl_link_get_master(link) != master) + err = -NLE_OPNOTSUPP; + +errout: + rtnl_link_put(link); + + return err; +} + +/** + * Add a link to a bond (enslave) + * @arg sock netlink socket + * @arg master bonding master + * @arg slave slave link to add to bond + * + * Constructs a RTM_NEWLINK or RTM_SETLINK message adding the slave to + * the master and sends the request via the specified netlink socket. + * + * @note The feature of enslaving/releasing via netlink has only been added + * recently to the kernel (Feb 2011). Also, the kernel does not signal + * if the operation is not supported. Therefore this function will + * verify if the master assignment has changed and will return + * -NLE_OPNOTSUPP if it did not. + * + * @see rtnl_link_bond_enslave_ifindex() + * @see rtnl_link_bond_release() + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_bond_enslave(struct nl_sock *sock, struct rtnl_link *master, + struct rtnl_link *slave) +{ + return rtnl_link_bond_enslave_ifindex(sock, + rtnl_link_get_ifindex(master), + rtnl_link_get_ifindex(slave)); +} + +/** + * Release a link from a bond + * @arg sock netlink socket + * @arg slave slave link to be released + * + * This function is identical to rtnl_link_bond_release() except that + * it takes an interface index instead of a rtnl_link object. + * + * @see rtnl_link_bond_release() + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_bond_release_ifindex(struct nl_sock *sock, int slave) +{ + return rtnl_link_bond_enslave_ifindex(sock, 0, slave); +} + +/** + * Release a link from a bond + * @arg sock netlink socket + * @arg slave slave link to be released + * + * Constructs a RTM_NEWLINK or RTM_SETLINK message releasing the slave from + * its master and sends the request via the specified netlink socket. + * + * @note The feature of enslaving/releasing via netlink has only been added + * recently to the kernel (Feb 2011). Also, the kernel does not signal + * if the operation is not supported. Therefore this function will + * verify if the master assignment has changed and will return + * -NLE_OPNOTSUPP if it did not. + * + * @see rtnl_link_bond_release_ifindex() + * @see rtnl_link_bond_enslave() + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_bond_release(struct nl_sock *sock, struct rtnl_link *slave) +{ + return rtnl_link_bond_release_ifindex(sock, + rtnl_link_get_ifindex(slave)); +} + +static struct rtnl_link_info_ops bonding_info_ops = { + .io_name = "bond", +}; + +static void __init bonding_init(void) +{ + rtnl_link_register_info(&bonding_info_ops); +} + +static void __exit bonding_exit(void) +{ + rtnl_link_unregister_info(&bonding_info_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/link/bridge.c b/libnetwork/libnl3/lib/route/link/bridge.c new file mode 100644 index 0000000..32fd38f --- /dev/null +++ b/libnetwork/libnl3/lib/route/link/bridge.c @@ -0,0 +1,83 @@ +/* + * lib/route/link/bridge.c AF_BRIDGE link oeprations + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf + */ + +#include +#include +#include +#include +#include + +struct bridge_data +{ + uint8_t b_port_state; +}; + +static void *bridge_alloc(struct rtnl_link *link) +{ + return calloc(1, sizeof(struct bridge_data)); +} + +static void *bridge_clone(struct rtnl_link *link, void *data) +{ + struct bridge_data *bd; + + if ((bd = bridge_alloc(link))) + memcpy(bd, data, sizeof(*bd)); + + return bd; +} + +static void bridge_free(struct rtnl_link *link, void *data) +{ + free(data); +} + +static int bridge_parse_protinfo(struct rtnl_link *link, struct nlattr *attr, + void *data) +{ + struct bridge_data *bd = data; + + bd->b_port_state = nla_get_u8(attr); + + return 0; +} + +static void bridge_dump_details(struct rtnl_link *link, + struct nl_dump_params *p, void *data) +{ + struct bridge_data *bd = data; + + nl_dump(p, "port-state %u ", bd->b_port_state); +} + +static const struct nla_policy protinfo_policy = { + .type = NLA_U8, +}; + +static struct rtnl_link_af_ops bridge_ops = { + .ao_family = AF_BRIDGE, + .ao_alloc = &bridge_alloc, + .ao_clone = &bridge_clone, + .ao_free = &bridge_free, + .ao_parse_protinfo = &bridge_parse_protinfo, + .ao_dump[NL_DUMP_DETAILS] = &bridge_dump_details, + .ao_protinfo_policy = &protinfo_policy, +}; + +static void __init bridge_init(void) +{ + rtnl_link_af_register(&bridge_ops); +} + +static void __exit bridge_exit(void) +{ + rtnl_link_af_unregister(&bridge_ops); +} diff --git a/libnetwork/libnl3/lib/route/link/dummy.c b/libnetwork/libnl3/lib/route/link/dummy.c new file mode 100644 index 0000000..c7dabc1 --- /dev/null +++ b/libnetwork/libnl3/lib/route/link/dummy.c @@ -0,0 +1,40 @@ +/* + * lib/route/link/dummy.c Dummy Interfaces + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2011 Thomas Graf + */ + +/** + * @ingroup link + * @defgroup dummy Dummy + * + * @details + * \b Link Type Name: "dummy" + * + * @{ + */ + +#include +#include +#include + +static struct rtnl_link_info_ops dummy_info_ops = { + .io_name = "dummy", +}; + +static void __init dummy_init(void) +{ + rtnl_link_register_info(&dummy_info_ops); +} + +static void __exit dummy_exit(void) +{ + rtnl_link_unregister_info(&dummy_info_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/link/inet.c b/libnetwork/libnl3/lib/route/link/inet.c new file mode 100644 index 0000000..a0e2318 --- /dev/null +++ b/libnetwork/libnl3/lib/route/link/inet.c @@ -0,0 +1,280 @@ +/* + * lib/route/link/inet.c AF_INET link operations + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf + */ + +/** + * @ingroup link_API + * @defgroup link_inet IPv4 Link Module + * @brief Implementation of IPv4 specific link attributes + * + * + * + * @par Example: Reading the value of IPV4_DEVCONF_FORWARDING + * @code + * struct nl_cache *cache; + * struct rtnl_link *link; + * uint32_t value; + * + * // Allocate a link cache + * rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache); + * + * // Search for the link we wish to see the value from + * link = rtnl_link_get_by_name(cache, "eth0"); + * + * // Read the value of the setting IPV4_DEVCONF_FORWARDING + * if (rtnl_link_inet_get_conf(link, IPV4_DEVCONF_FORWARDING, &value) < 0) + * // Error: Unable to read config setting + * + * printf("forwarding is %s\n", value ? "enabled" : "disabled"); + * @endcode + * + * @par Example: Changing the value of IPV4_DEVCONF_FOWARDING + * @code + * // + * // ... Continueing from the previous example ... + * // + * + * struct rtnl_link *new; + * + * // Allocate a new link to store the changes we wish to make. + * new = rtnl_link_alloc(); + * + * // Set IPV4_DEVCONF_FORWARDING to '1' + * rtnl_link_inet_set_conf(new, IPV4_DEVCONF_FORWARDING, 1); + * + * // Send the change request to the kernel. + * rtnl_link_change(sock, link, new, 0); + * @endcode + * + * @{ + */ + + +#include +#include +#include +#include +#include + +/** @cond SKIP */ +struct inet_data +{ + uint8_t i_confset[IPV4_DEVCONF_MAX]; + uint32_t i_conf[IPV4_DEVCONF_MAX]; +}; +/** @endcond */ + +static void *inet_alloc(struct rtnl_link *link) +{ + return calloc(1, sizeof(struct inet_data)); +} + +static void *inet_clone(struct rtnl_link *link, void *data) +{ + struct inet_data *id; + + if ((id = inet_alloc(link))) + memcpy(id, data, sizeof(*id)); + + return id; +} + +static void inet_free(struct rtnl_link *link, void *data) +{ + free(data); +} + +static struct nla_policy inet_policy[IFLA_INET6_MAX+1] = { + [IFLA_INET_CONF] = { .minlen = IPV4_DEVCONF_MAX * 4 }, +}; + +static int inet_parse_af(struct rtnl_link *link, struct nlattr *attr, void *data) +{ + struct inet_data *id = data; + struct nlattr *tb[IFLA_INET_MAX+1]; + int err; + + err = nla_parse_nested(tb, IFLA_INET_MAX, attr, inet_policy); + if (err < 0) + return err; + + if (tb[IFLA_INET_CONF]) + nla_memcpy(&id->i_conf, tb[IFLA_INET_CONF], sizeof(id->i_conf)); + + return 0; +} + +static int inet_fill_af(struct rtnl_link *link, struct nl_msg *msg, void *data) +{ + struct inet_data *id = data; + struct nlattr *nla; + int i; + + if (!(nla = nla_nest_start(msg, IFLA_INET_CONF))) + return -NLE_MSGSIZE; + + for (i = 0; i < IPV4_DEVCONF_MAX; i++) + if (id->i_confset[i]) + NLA_PUT_U32(msg, i+1, id->i_conf[i]); + + nla_nest_end(msg, nla); + + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +static const struct trans_tbl inet_devconf[] = { + __ADD(IPV4_DEVCONF_FORWARDING, forwarding) + __ADD(IPV4_DEVCONF_MC_FORWARDING, mc_forwarding) + __ADD(IPV4_DEVCONF_PROXY_ARP, proxy_arp) + __ADD(IPV4_DEVCONF_ACCEPT_REDIRECTS, accept_redirects) + __ADD(IPV4_DEVCONF_SECURE_REDIRECTS, secure_redirects) + __ADD(IPV4_DEVCONF_SEND_REDIRECTS, send_redirects) + __ADD(IPV4_DEVCONF_SHARED_MEDIA, shared_media) + __ADD(IPV4_DEVCONF_RP_FILTER, rp_filter) + __ADD(IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route) + __ADD(IPV4_DEVCONF_BOOTP_RELAY, bootp_relay) + __ADD(IPV4_DEVCONF_LOG_MARTIANS, log_martians) + __ADD(IPV4_DEVCONF_TAG, tag) + __ADD(IPV4_DEVCONF_ARPFILTER, arpfilter) + __ADD(IPV4_DEVCONF_MEDIUM_ID, medium_id) + __ADD(IPV4_DEVCONF_NOXFRM, noxfrm) + __ADD(IPV4_DEVCONF_NOPOLICY, nopolicy) + __ADD(IPV4_DEVCONF_FORCE_IGMP_VERSION, force_igmp_version) + __ADD(IPV4_DEVCONF_ARP_ANNOUNCE, arp_announce) + __ADD(IPV4_DEVCONF_ARP_IGNORE, arp_ignore) + __ADD(IPV4_DEVCONF_PROMOTE_SECONDARIES, promote_secondaries) + __ADD(IPV4_DEVCONF_ARP_ACCEPT, arp_accept) + __ADD(IPV4_DEVCONF_ARP_NOTIFY, arp_notify) + __ADD(IPV4_DEVCONF_ACCEPT_LOCAL, accept_local) + __ADD(IPV4_DEVCONF_SRC_VMARK, src_vmark) + __ADD(IPV4_DEVCONF_PROXY_ARP_PVLAN, proxy_arp_pvlan) +}; + +const char *rtnl_link_inet_devconf2str(int type, char *buf, size_t len) +{ + return __type2str(type, buf, len, inet_devconf, + ARRAY_SIZE(inet_devconf)); +} + +int rtnl_link_inet_str2devconf(const char *name) +{ + return __str2type(name, inet_devconf, ARRAY_SIZE(inet_devconf)); +} + +static void inet_dump_details(struct rtnl_link *link, + struct nl_dump_params *p, void *data) +{ + struct inet_data *id = data; + char buf[64]; + int i, n = 0; + + nl_dump_line(p, " ipv4 devconf:\n"); + nl_dump_line(p, " "); + + for (i = 0; i < IPV4_DEVCONF_MAX; i++) { + nl_dump_line(p, "%-19s %3u", + rtnl_link_inet_devconf2str(i+1, buf, sizeof(buf)), + id->i_conf[i]); + + if (++n == 3) { + nl_dump(p, "\n"); + nl_dump_line(p, " "); + n = 0; + } else + nl_dump(p, " "); + } + + if (n != 0) + nl_dump(p, "\n"); +} + +static struct rtnl_link_af_ops inet_ops = { + .ao_family = AF_INET, + .ao_alloc = &inet_alloc, + .ao_clone = &inet_clone, + .ao_free = &inet_free, + .ao_parse_af = &inet_parse_af, + .ao_fill_af = &inet_fill_af, + .ao_dump[NL_DUMP_DETAILS] = &inet_dump_details, +}; + +/** + * Get value of a ipv4 link configuration setting + * @arg link Link object + * @arg cfgid Configuration identifier + * @arg res Result pointer + * + * Stores the value of the specified configuration setting in the provided + * result pointer. + * + * @return 0 on success or a negative error code. + * @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX + * @return -NLE_NOATTR configuration setting not available + */ +int rtnl_link_inet_get_conf(struct rtnl_link *link, const unsigned int cfgid, + uint32_t *res) +{ + struct inet_data *id; + + if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX) + return -NLE_RANGE; + + if (!(id = rtnl_link_af_alloc(link, &inet_ops))) + return -NLE_NOATTR; + + *res = id->i_conf[cfgid - 1]; + + return 0; +} + +/** + * Change value of a ipv4 link configuration setting + * @arg link Link object + * @arg cfgid Configuration identifier + * @arg value New value + * + * Changes the value in the per link ipv4 configuration array. + * + * @return 0 on success or a negative error code. + * @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX + * @return -NLE_NOMEM memory allocation failed + */ +int rtnl_link_inet_set_conf(struct rtnl_link *link, const unsigned int cfgid, + uint32_t value) +{ + struct inet_data *id; + + if (!(id = rtnl_link_af_alloc(link, &inet_ops))) + return -NLE_NOMEM; + + if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX) + return -NLE_RANGE; + + id->i_confset[cfgid - 1] = 1; + id->i_conf[cfgid - 1] = value; + + return 0; +} + + +static void __init inet_init(void) +{ + rtnl_link_af_register(&inet_ops); +} + +static void __exit inet_exit(void) +{ + rtnl_link_af_unregister(&inet_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/link/inet6.c b/libnetwork/libnl3/lib/route/link/inet6.c new file mode 100644 index 0000000..5f75342 --- /dev/null +++ b/libnetwork/libnl3/lib/route/link/inet6.c @@ -0,0 +1,377 @@ +/* + * lib/route/link/inet6.c AF_INET6 link operations + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf + */ + +#include +#include +#include +#include +#include + +struct inet6_data +{ + uint32_t i6_flags; + struct ifla_cacheinfo i6_cacheinfo; + uint32_t i6_conf[DEVCONF_MAX]; +}; + +static void *inet6_alloc(struct rtnl_link *link) +{ + return calloc(1, sizeof(struct inet6_data)); +} + +static void *inet6_clone(struct rtnl_link *link, void *data) +{ + struct inet6_data *i6; + + if ((i6 = inet6_alloc(link))) + memcpy(i6, data, sizeof(*i6)); + + return i6; +} + +static void inet6_free(struct rtnl_link *link, void *data) +{ + free(data); +} + +static struct nla_policy inet6_policy[IFLA_INET6_MAX+1] = { + [IFLA_INET6_FLAGS] = { .type = NLA_U32 }, + [IFLA_INET6_CACHEINFO] = { .minlen = sizeof(struct ifla_cacheinfo) }, + [IFLA_INET6_CONF] = { .minlen = DEVCONF_MAX * 4 }, + [IFLA_INET6_STATS] = { .minlen = __IPSTATS_MIB_MAX * 8 }, + [IFLA_INET6_ICMP6STATS] = { .minlen = __ICMP6_MIB_MAX * 8 }, +}; + +static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr, + void *data) +{ + struct inet6_data *i6 = data; + struct nlattr *tb[IFLA_INET6_MAX+1]; + int err; + + err = nla_parse_nested(tb, IFLA_INET6_MAX, attr, inet6_policy); + if (err < 0) + return err; + + if (tb[IFLA_INET6_FLAGS]) + i6->i6_flags = nla_get_u32(tb[IFLA_INET6_FLAGS]); + + if (tb[IFLA_INET6_CACHEINFO]) + nla_memcpy(&i6->i6_cacheinfo, tb[IFLA_INET6_CACHEINFO], + sizeof(i6->i6_cacheinfo)); + + if (tb[IFLA_INET6_CONF]) + nla_memcpy(&i6->i6_conf, tb[IFLA_INET6_CONF], + sizeof(i6->i6_conf)); + + /* + * Due to 32bit data alignment, these addresses must be copied to an + * aligned location prior to access. + */ + if (tb[IFLA_INET6_STATS]) { + unsigned char *cnt = nla_data(tb[IFLA_INET6_STATS]); + uint64_t stat; + int i; + + for (i = 1; i < __IPSTATS_MIB_MAX; i++) { + memcpy(&stat, &cnt[i * sizeof(stat)], sizeof(stat)); + rtnl_link_set_stat(link, RTNL_LINK_IP6_INPKTS + i - 1, + stat); + } + } + + if (tb[IFLA_INET6_ICMP6STATS]) { + unsigned char *cnt = nla_data(tb[IFLA_INET6_ICMP6STATS]); + uint64_t stat; + int i; + + for (i = 1; i < __ICMP6_MIB_MAX; i++) { + memcpy(&stat, &cnt[i * sizeof(stat)], sizeof(stat)); + rtnl_link_set_stat(link, RTNL_LINK_ICMP6_INMSGS + i - 1, + stat); + } + } + + return 0; +} + +/* These live in include/net/if_inet6.h and should be moved to include/linux */ +#define IF_RA_OTHERCONF 0x80 +#define IF_RA_MANAGED 0x40 +#define IF_RA_RCVD 0x20 +#define IF_RS_SENT 0x10 +#define IF_READY 0x80000000 + +static const struct trans_tbl inet6_flags[] = { + __ADD(IF_RA_OTHERCONF, ra_otherconf) + __ADD(IF_RA_MANAGED, ra_managed) + __ADD(IF_RA_RCVD, ra_rcvd) + __ADD(IF_RS_SENT, rs_sent) + __ADD(IF_READY, ready) +}; + +static char *inet6_flags2str(int flags, char *buf, size_t len) +{ + return __flags2str(flags, buf, len, inet6_flags, + ARRAY_SIZE(inet6_flags)); +} + +static const struct trans_tbl inet6_devconf[] = { + __ADD(DEVCONF_FORWARDING, forwarding) + __ADD(DEVCONF_HOPLIMIT, hoplimit) + __ADD(DEVCONF_MTU6, mtu6) + __ADD(DEVCONF_ACCEPT_RA, accept_ra) + __ADD(DEVCONF_ACCEPT_REDIRECTS, accept_redirects) + __ADD(DEVCONF_AUTOCONF, autoconf) + __ADD(DEVCONF_DAD_TRANSMITS, dad_transmits) + __ADD(DEVCONF_RTR_SOLICITS, rtr_solicits) + __ADD(DEVCONF_RTR_SOLICIT_INTERVAL, rtr_solicit_interval) + __ADD(DEVCONF_RTR_SOLICIT_DELAY, rtr_solicit_delay) + __ADD(DEVCONF_USE_TEMPADDR, use_tempaddr) + __ADD(DEVCONF_TEMP_VALID_LFT, temp_valid_lft) + __ADD(DEVCONF_TEMP_PREFERED_LFT, temp_prefered_lft) + __ADD(DEVCONF_REGEN_MAX_RETRY, regen_max_retry) + __ADD(DEVCONF_MAX_DESYNC_FACTOR, max_desync_factor) + __ADD(DEVCONF_MAX_ADDRESSES, max_addresses) + __ADD(DEVCONF_FORCE_MLD_VERSION, force_mld_version) + __ADD(DEVCONF_ACCEPT_RA_DEFRTR, accept_ra_defrtr) + __ADD(DEVCONF_ACCEPT_RA_PINFO, accept_ra_pinfo) + __ADD(DEVCONF_ACCEPT_RA_RTR_PREF, accept_ra_rtr_pref) + __ADD(DEVCONF_RTR_PROBE_INTERVAL, rtr_probe_interval) + __ADD(DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN, accept_ra_rt_info) + __ADD(DEVCONF_PROXY_NDP, proxy_ndp) + __ADD(DEVCONF_OPTIMISTIC_DAD, optimistic_dad) + __ADD(DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route) + __ADD(DEVCONF_MC_FORWARDING, mc_forwarding) + __ADD(DEVCONF_DISABLE_IPV6, disable_ipv6) + __ADD(DEVCONF_ACCEPT_DAD, accept_dad) + __ADD(DEVCONF_FORCE_TLLAO, force_tllao) +}; + +static char *inet6_devconf2str(int type, char *buf, size_t len) +{ + return __type2str(type, buf, len, inet6_devconf, + ARRAY_SIZE(inet6_devconf)); +} + + +static void inet6_dump_details(struct rtnl_link *link, + struct nl_dump_params *p, void *data) +{ + struct inet6_data *i6 = data; + char buf[64], buf2[64]; + int i, n = 0; + + nl_dump_line(p, " ipv6 max-reasm-len %s", + nl_size2str(i6->i6_cacheinfo.max_reasm_len, buf, sizeof(buf))); + + nl_dump(p, " <%s>\n", + inet6_flags2str(i6->i6_flags, buf, sizeof(buf))); + + + nl_dump_line(p, " create-stamp %.2fs reachable-time %s", + (double) i6->i6_cacheinfo.tstamp / 100., + nl_msec2str(i6->i6_cacheinfo.reachable_time, buf, sizeof(buf))); + + nl_dump(p, " retrans-time %s\n", + nl_msec2str(i6->i6_cacheinfo.retrans_time, buf, sizeof(buf))); + + nl_dump_line(p, " devconf:\n"); + nl_dump_line(p, " "); + + for (i = 0; i < DEVCONF_MAX; i++) { + uint32_t value = i6->i6_conf[i]; + int x, offset; + + switch (i) { + case DEVCONF_TEMP_VALID_LFT: + case DEVCONF_TEMP_PREFERED_LFT: + nl_msec2str((uint64_t) value * 1000., buf2, sizeof(buf2)); + break; + + case DEVCONF_RTR_PROBE_INTERVAL: + case DEVCONF_RTR_SOLICIT_INTERVAL: + case DEVCONF_RTR_SOLICIT_DELAY: + nl_msec2str(value, buf2, sizeof(buf2)); + break; + + default: + snprintf(buf2, sizeof(buf2), "%u", value); + break; + + } + + inet6_devconf2str(i, buf, sizeof(buf)); + + offset = 23 - strlen(buf2); + if (offset < 0) + offset = 0; + + for (x = strlen(buf); x < offset; x++) + buf[x] = ' '; + + strncpy(&buf[offset], buf2, strlen(buf2)); + + nl_dump_line(p, "%s", buf); + + if (++n == 3) { + nl_dump(p, "\n"); + nl_dump_line(p, " "); + n = 0; + } else + nl_dump(p, " "); + } + + if (n != 0) + nl_dump(p, "\n"); +} + +static void inet6_dump_stats(struct rtnl_link *link, + struct nl_dump_params *p, void *data) +{ + double octets; + char *octetsUnit; + + nl_dump(p, " IPv6: InPkts InOctets " + " InDiscards InDelivers\n"); + nl_dump(p, " %18llu ", link->l_stats[RTNL_LINK_IP6_INPKTS]); + + octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INOCTETS], + &octetsUnit); + if (octets) + nl_dump(p, "%14.2f %3s ", octets, octetsUnit); + else + nl_dump(p, "%16llu B ", 0); + + nl_dump(p, "%18llu %18llu\n", + link->l_stats[RTNL_LINK_IP6_INDISCARDS], + link->l_stats[RTNL_LINK_IP6_INDELIVERS]); + + nl_dump(p, " OutPkts OutOctets " + " OutDiscards OutForwards\n"); + + nl_dump(p, " %18llu ", link->l_stats[RTNL_LINK_IP6_OUTPKTS]); + + octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTOCTETS], + &octetsUnit); + if (octets) + nl_dump(p, "%14.2f %3s ", octets, octetsUnit); + else + nl_dump(p, "%16llu B ", 0); + + nl_dump(p, "%18llu %18llu\n", + link->l_stats[RTNL_LINK_IP6_OUTDISCARDS], + link->l_stats[RTNL_LINK_IP6_OUTFORWDATAGRAMS]); + + nl_dump(p, " InMcastPkts InMcastOctets " + " InBcastPkts InBcastOctests\n"); + + nl_dump(p, " %18llu ", link->l_stats[RTNL_LINK_IP6_INMCASTPKTS]); + + octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INMCASTOCTETS], + &octetsUnit); + if (octets) + nl_dump(p, "%14.2f %3s ", octets, octetsUnit); + else + nl_dump(p, "%16llu B ", 0); + + nl_dump(p, "%18llu ", link->l_stats[RTNL_LINK_IP6_INBCASTPKTS]); + octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INBCASTOCTETS], + &octetsUnit); + if (octets) + nl_dump(p, "%14.2f %3s\n", octets, octetsUnit); + else + nl_dump(p, "%16llu B\n", 0); + + nl_dump(p, " OutMcastPkts OutMcastOctets " + " OutBcastPkts OutBcastOctests\n"); + + nl_dump(p, " %18llu ", link->l_stats[RTNL_LINK_IP6_OUTMCASTPKTS]); + + octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTMCASTOCTETS], + &octetsUnit); + if (octets) + nl_dump(p, "%14.2f %3s ", octets, octetsUnit); + else + nl_dump(p, "%16llu B ", 0); + + nl_dump(p, "%18llu ", link->l_stats[RTNL_LINK_IP6_OUTBCASTPKTS]); + octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTBCASTOCTETS], + &octetsUnit); + if (octets) + nl_dump(p, "%14.2f %3s\n", octets, octetsUnit); + else + nl_dump(p, "%16llu B\n", 0); + + nl_dump(p, " ReasmOKs ReasmFails " + " ReasmReqds ReasmTimeout\n"); + nl_dump(p, " %18llu %18llu %18llu %18llu\n", + link->l_stats[RTNL_LINK_IP6_REASMOKS], + link->l_stats[RTNL_LINK_IP6_REASMFAILS], + link->l_stats[RTNL_LINK_IP6_REASMREQDS], + link->l_stats[RTNL_LINK_IP6_REASMTIMEOUT]); + + nl_dump(p, " FragOKs FragFails " + " FragCreates\n"); + nl_dump(p, " %18llu %18llu %18llu\n", + link->l_stats[RTNL_LINK_IP6_FRAGOKS], + link->l_stats[RTNL_LINK_IP6_FRAGFAILS], + link->l_stats[RTNL_LINK_IP6_FRAGCREATES]); + + nl_dump(p, " InHdrErrors InTooBigErrors " + " InNoRoutes InAddrErrors\n"); + nl_dump(p, " %18llu %18llu %18llu %18llu\n", + link->l_stats[RTNL_LINK_IP6_INHDRERRORS], + link->l_stats[RTNL_LINK_IP6_INTOOBIGERRORS], + link->l_stats[RTNL_LINK_IP6_INNOROUTES], + link->l_stats[RTNL_LINK_IP6_INADDRERRORS]); + + nl_dump(p, " InUnknownProtos InTruncatedPkts " + " OutNoRoutes\n"); + nl_dump(p, " %18llu %18llu %18llu\n", + link->l_stats[RTNL_LINK_IP6_INUNKNOWNPROTOS], + link->l_stats[RTNL_LINK_IP6_INTRUNCATEDPKTS], + link->l_stats[RTNL_LINK_IP6_OUTNOROUTES]); + + nl_dump(p, " ICMPv6: InMsgs InErrors " + " OutMsgs OutErrors\n"); + nl_dump(p, " %18llu %18llu %18llu %18llu\n", + link->l_stats[RTNL_LINK_ICMP6_INMSGS], + link->l_stats[RTNL_LINK_ICMP6_INERRORS], + link->l_stats[RTNL_LINK_ICMP6_OUTMSGS], + link->l_stats[RTNL_LINK_ICMP6_OUTERRORS]); +} + +static const struct nla_policy protinfo_policy = { + .type = NLA_NESTED, +}; + +static struct rtnl_link_af_ops inet6_ops = { + .ao_family = AF_INET6, + .ao_alloc = &inet6_alloc, + .ao_clone = &inet6_clone, + .ao_free = &inet6_free, + .ao_parse_protinfo = &inet6_parse_protinfo, + .ao_parse_af = &inet6_parse_protinfo, + .ao_dump[NL_DUMP_DETAILS] = &inet6_dump_details, + .ao_dump[NL_DUMP_STATS] = &inet6_dump_stats, + .ao_protinfo_policy = &protinfo_policy, +}; + +static void __init inet6_init(void) +{ + rtnl_link_af_register(&inet6_ops); +} + +static void __exit inet6_exit(void) +{ + rtnl_link_af_unregister(&inet6_ops); +} diff --git a/libnetwork/libnl3/lib/route/link/vlan.c b/libnetwork/libnl3/lib/route/link/vlan.c new file mode 100644 index 0000000..a30ff77 --- /dev/null +++ b/libnetwork/libnl3/lib/route/link/vlan.c @@ -0,0 +1,565 @@ +/* + * lib/route/link/vlan.c VLAN Link Info + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2010 Thomas Graf + */ + +/** + * @ingroup link + * @defgroup vlan VLAN + * Virtual LAN link module + * + * @details + * \b Link Type Name: "vlan" + * + * @route_doc{link_vlan, VLAN Documentation} + * + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/** @cond SKIP */ +#define VLAN_HAS_ID (1<<0) +#define VLAN_HAS_FLAGS (1<<1) +#define VLAN_HAS_INGRESS_QOS (1<<2) +#define VLAN_HAS_EGRESS_QOS (1<<3) + +struct vlan_info +{ + uint16_t vi_vlan_id; + uint32_t vi_flags; + uint32_t vi_flags_mask; + uint32_t vi_ingress_qos[VLAN_PRIO_MAX+1]; + uint32_t vi_negress; + uint32_t vi_egress_size; + struct vlan_map * vi_egress_qos; + uint32_t vi_mask; +}; + +/** @endcond */ + +static struct nla_policy vlan_policy[IFLA_VLAN_MAX+1] = { + [IFLA_VLAN_ID] = { .type = NLA_U16 }, + [IFLA_VLAN_FLAGS] = { .minlen = sizeof(struct ifla_vlan_flags) }, + [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED }, + [IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED }, +}; + +static int vlan_alloc(struct rtnl_link *link) +{ + struct vlan_info *vi; + + if ((vi = calloc(1, sizeof(*vi))) == NULL) + return -NLE_NOMEM; + + link->l_info = vi; + + return 0; +} + +static int vlan_parse(struct rtnl_link *link, struct nlattr *data, + struct nlattr *xstats) +{ + struct nlattr *tb[IFLA_VLAN_MAX+1]; + struct vlan_info *vi; + int err; + + NL_DBG(3, "Parsing VLAN link info"); + + if ((err = nla_parse_nested(tb, IFLA_VLAN_MAX, data, vlan_policy)) < 0) + goto errout; + + if ((err = vlan_alloc(link)) < 0) + goto errout; + + vi = link->l_info; + + if (tb[IFLA_VLAN_ID]) { + vi->vi_vlan_id = nla_get_u16(tb[IFLA_VLAN_ID]); + vi->vi_mask |= VLAN_HAS_ID; + } + + if (tb[IFLA_VLAN_FLAGS]) { + struct ifla_vlan_flags flags; + nla_memcpy(&flags, tb[IFLA_VLAN_FLAGS], sizeof(flags)); + + vi->vi_flags = flags.flags; + vi->vi_mask |= VLAN_HAS_FLAGS; + } + + if (tb[IFLA_VLAN_INGRESS_QOS]) { + struct ifla_vlan_qos_mapping *map; + struct nlattr *nla; + int remaining; + + memset(vi->vi_ingress_qos, 0, sizeof(vi->vi_ingress_qos)); + + nla_for_each_nested(nla, tb[IFLA_VLAN_INGRESS_QOS], remaining) { + if (nla_len(nla) < sizeof(*map)) + return -NLE_INVAL; + + map = nla_data(nla); + if (map->from < 0 || map->from > VLAN_PRIO_MAX) { + return -NLE_INVAL; + } + + vi->vi_ingress_qos[map->from] = map->to; + } + + vi->vi_mask |= VLAN_HAS_INGRESS_QOS; + } + + if (tb[IFLA_VLAN_EGRESS_QOS]) { + struct ifla_vlan_qos_mapping *map; + struct nlattr *nla; + int remaining, i = 0; + + nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) { + if (nla_len(nla) < sizeof(*map)) + return -NLE_INVAL; + i++; + } + + /* align to have a little reserve */ + vi->vi_egress_size = (i + 32) & ~31; + vi->vi_egress_qos = calloc(vi->vi_egress_size, sizeof(*map)); + if (vi->vi_egress_qos == NULL) + return -NLE_NOMEM; + + i = 0; + nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) { + map = nla_data(nla); + NL_DBG(4, "Assigning egress qos mapping %d\n", i); + vi->vi_egress_qos[i].vm_from = map->from; + vi->vi_egress_qos[i++].vm_to = map->to; + } + + vi->vi_negress = i; + vi->vi_mask |= VLAN_HAS_EGRESS_QOS; + } + + err = 0; +errout: + return err; +} + +static void vlan_free(struct rtnl_link *link) +{ + struct vlan_info *vi = link->l_info; + + if (vi) { + free(vi->vi_egress_qos); + vi->vi_egress_qos = NULL; + } + + free(vi); + link->l_info = NULL; +} + +static void vlan_dump_line(struct rtnl_link *link, struct nl_dump_params *p) +{ + struct vlan_info *vi = link->l_info; + + nl_dump(p, "vlan-id %d", vi->vi_vlan_id); +} + +static void vlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p) +{ + struct vlan_info *vi = link->l_info; + int i, printed; + char buf[64]; + + rtnl_link_vlan_flags2str(vi->vi_flags, buf, sizeof(buf)); + nl_dump_line(p, " vlan-info id %d <%s>\n", vi->vi_vlan_id, buf); + + if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) { + nl_dump_line(p, + " ingress vlan prio -> qos/socket prio mapping:\n"); + for (i = 0, printed = 0; i <= VLAN_PRIO_MAX; i++) { + if (vi->vi_ingress_qos[i]) { + if (printed == 0) + nl_dump_line(p, " "); + nl_dump(p, "%x -> %#08x, ", + i, vi->vi_ingress_qos[i]); + if (printed++ == 3) { + nl_dump(p, "\n"); + printed = 0; + } + } + } + + if (printed > 0 && printed != 4) + nl_dump(p, "\n"); + } + + if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) { + nl_dump_line(p, + " egress qos/socket prio -> vlan prio mapping:\n"); + for (i = 0, printed = 0; i < vi->vi_negress; i++) { + if (printed == 0) + nl_dump_line(p, " "); + nl_dump(p, "%#08x -> %x, ", + vi->vi_egress_qos[i].vm_from, + vi->vi_egress_qos[i].vm_to); + if (printed++ == 3) { + nl_dump(p, "\n"); + printed = 0; + } + } + + if (printed > 0 && printed != 4) + nl_dump(p, "\n"); + } +} + +static int vlan_clone(struct rtnl_link *dst, struct rtnl_link *src) +{ + struct vlan_info *vdst, *vsrc = src->l_info; + int err; + + dst->l_info = NULL; + if ((err = rtnl_link_set_type(dst, "vlan")) < 0) + return err; + vdst = dst->l_info; + + vdst->vi_egress_qos = calloc(vsrc->vi_egress_size, + sizeof(struct vlan_map)); + if (!vdst->vi_egress_qos) + return -NLE_NOMEM; + + memcpy(vdst->vi_egress_qos, vsrc->vi_egress_qos, + vsrc->vi_egress_size * sizeof(struct vlan_map)); + + return 0; +} + +static int vlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link) +{ + struct vlan_info *vi = link->l_info; + struct nlattr *data; + + if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) + return -NLE_MSGSIZE; + + if (vi->vi_mask & VLAN_HAS_ID) + NLA_PUT_U16(msg, IFLA_VLAN_ID, vi->vi_vlan_id); + + if (vi->vi_mask & VLAN_HAS_FLAGS) { + struct ifla_vlan_flags flags = { + .flags = vi->vi_flags, + .mask = vi->vi_flags_mask, + }; + + NLA_PUT(msg, IFLA_VLAN_FLAGS, sizeof(flags), &flags); + } + + if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) { + struct ifla_vlan_qos_mapping map; + struct nlattr *qos; + int i; + + if (!(qos = nla_nest_start(msg, IFLA_VLAN_INGRESS_QOS))) + goto nla_put_failure; + + for (i = 0; i <= VLAN_PRIO_MAX; i++) { + if (vi->vi_ingress_qos[i]) { + map.from = i; + map.to = vi->vi_ingress_qos[i]; + + NLA_PUT(msg, i, sizeof(map), &map); + } + } + + nla_nest_end(msg, qos); + } + + if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) { + struct ifla_vlan_qos_mapping map; + struct nlattr *qos; + int i; + + if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS))) + goto nla_put_failure; + + for (i = 0; i < vi->vi_negress; i++) { + map.from = vi->vi_egress_qos[i].vm_from; + map.to = vi->vi_egress_qos[i].vm_to; + + NLA_PUT(msg, i, sizeof(map), &map); + } + + nla_nest_end(msg, qos); + } + + nla_nest_end(msg, data); + +nla_put_failure: + + return 0; +} + +static struct rtnl_link_info_ops vlan_info_ops = { + .io_name = "vlan", + .io_alloc = vlan_alloc, + .io_parse = vlan_parse, + .io_dump = { + [NL_DUMP_LINE] = vlan_dump_line, + [NL_DUMP_DETAILS] = vlan_dump_details, + }, + .io_clone = vlan_clone, + .io_put_attrs = vlan_put_attrs, + .io_free = vlan_free, +}; + +/** @cond SKIP */ +#define IS_VLAN_LINK_ASSERT(link) \ + if ((link)->l_info_ops != &vlan_info_ops) { \ + APPBUG("Link is not a vlan link. set type \"vlan\" first."); \ + return -NLE_OPNOTSUPP; \ + } +/** @endcond */ + +/** + * @name VLAN Object + * @{ + */ + +/** + * Check if link is a VLAN link + * @arg link Link object + * + * @return True if link is a VLAN link, otherwise false is returned. + */ +int rtnl_link_is_vlan(struct rtnl_link *link) +{ + return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vlan"); +} + +/** + * Set VLAN ID + * @arg link Link object + * @arg id VLAN identifier + * + * @return 0 on success or a negative error code + */ +int rtnl_link_vlan_set_id(struct rtnl_link *link, uint16_t id) +{ + struct vlan_info *vi = link->l_info; + + IS_VLAN_LINK_ASSERT(link); + + vi->vi_vlan_id = id; + vi->vi_mask |= VLAN_HAS_ID; + + return 0; +} + +/** + * Get VLAN Id + * @arg link Link object + * + * @return VLAN id, 0 if not set or a negative error code. + */ +int rtnl_link_vlan_get_id(struct rtnl_link *link) +{ + struct vlan_info *vi = link->l_info; + + IS_VLAN_LINK_ASSERT(link); + + if (vi->vi_mask & VLAN_HAS_ID) + return vi->vi_vlan_id; + else + return 0; +} + +/** + * Set VLAN flags + * @arg link Link object + * @arg flags VLAN flags + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_vlan_set_flags(struct rtnl_link *link, unsigned int flags) +{ + struct vlan_info *vi = link->l_info; + + IS_VLAN_LINK_ASSERT(link); + + vi->vi_flags_mask |= flags; + vi->vi_flags |= flags; + vi->vi_mask |= VLAN_HAS_FLAGS; + + return 0; +} + +/** + * Unset VLAN flags + * @arg link Link object + * @arg flags VLAN flags + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_vlan_unset_flags(struct rtnl_link *link, unsigned int flags) +{ + struct vlan_info *vi = link->l_info; + + IS_VLAN_LINK_ASSERT(link); + + vi->vi_flags_mask |= flags; + vi->vi_flags &= ~flags; + vi->vi_mask |= VLAN_HAS_FLAGS; + + return 0; +} + +/** + * Get VLAN flags + * @arg link Link object + * + * @return VLAN flags, 0 if none set, or a negative error code. + */ +int rtnl_link_vlan_get_flags(struct rtnl_link *link) +{ + struct vlan_info *vi = link->l_info; + + IS_VLAN_LINK_ASSERT(link); + + return vi->vi_flags; +} + +/** @} */ + +/** + * @name Quality of Service + * @{ + */ + +int rtnl_link_vlan_set_ingress_map(struct rtnl_link *link, int from, + uint32_t to) +{ + struct vlan_info *vi = link->l_info; + + IS_VLAN_LINK_ASSERT(link); + + if (from < 0 || from > VLAN_PRIO_MAX) + return -NLE_INVAL; + + vi->vi_ingress_qos[from] = to; + vi->vi_mask |= VLAN_HAS_INGRESS_QOS; + + return 0; +} + +uint32_t *rtnl_link_vlan_get_ingress_map(struct rtnl_link *link) +{ + struct vlan_info *vi = link->l_info; + + if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) + return NULL; + + if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) + return vi->vi_ingress_qos; + else + return NULL; +} + +int rtnl_link_vlan_set_egress_map(struct rtnl_link *link, uint32_t from, int to) +{ + struct vlan_info *vi = link->l_info; + + if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) + return -NLE_OPNOTSUPP; + + if (to < 0 || to > VLAN_PRIO_MAX) + return -NLE_INVAL; + + if (vi->vi_negress >= vi->vi_egress_size) { + int new_size = vi->vi_egress_size + 32; + void *ptr; + + ptr = realloc(vi->vi_egress_qos, new_size); + if (!ptr) + return -NLE_NOMEM; + + vi->vi_egress_qos = ptr; + vi->vi_egress_size = new_size; + } + + vi->vi_egress_qos[vi->vi_negress].vm_from = from; + vi->vi_egress_qos[vi->vi_negress].vm_to = to; + vi->vi_negress++; + vi->vi_mask |= VLAN_HAS_EGRESS_QOS; + + return 0; +} + +struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *link, + int *negress) +{ + struct vlan_info *vi = link->l_info; + + if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) + return NULL; + + if (negress == NULL) + return NULL; + + if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) { + *negress = vi->vi_negress; + return vi->vi_egress_qos; + } else { + *negress = 0; + return NULL; + } +} + +/** @} */ + +static const struct trans_tbl vlan_flags[] = { + __ADD(VLAN_FLAG_REORDER_HDR, reorder_hdr) +}; + +/** + * @name Flag Translation + * @{ + */ + +char *rtnl_link_vlan_flags2str(int flags, char *buf, size_t len) +{ + return __flags2str(flags, buf, len, vlan_flags, ARRAY_SIZE(vlan_flags)); +} + +int rtnl_link_vlan_str2flags(const char *name) +{ + return __str2flags(name, vlan_flags, ARRAY_SIZE(vlan_flags)); +} + +/** @} */ + + +static void __init vlan_init(void) +{ + rtnl_link_register_info(&vlan_info_ops); +} + +static void __exit vlan_exit(void) +{ + rtnl_link_unregister_info(&vlan_info_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/neigh.c b/libnetwork/libnl3/lib/route/neigh.c new file mode 100644 index 0000000..7985d34 --- /dev/null +++ b/libnetwork/libnl3/lib/route/neigh.c @@ -0,0 +1,846 @@ +/* + * lib/route/neigh.c Neighbours + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup rtnl + * @defgroup neigh Neighbours + * @brief + * + * The neighbour table establishes bindings between protocol addresses and + * link layer addresses for hosts sharing the same physical link. This + * module allows you to access and manipulate the content of these tables. + * + * @par Neighbour States + * @code + * NUD_INCOMPLETE + * NUD_REACHABLE + * NUD_STALE + * NUD_DELAY + * NUD_PROBE + * NUD_FAILED + * NUD_NOARP + * NUD_PERMANENT + * @endcode + * + * @par Neighbour Flags + * @code + * NTF_USE + * NTF_PROXY + * NTF_ROUTER + * @endcode + * + * @par Neighbour Identification + * A neighbour is uniquely identified by the attributes listed below, whenever + * you refer to an existing neighbour all of the attributes must be set. + * Neighbours from caches automatically have all required attributes set. + * - interface index (rtnl_neigh_set_ifindex()) + * - destination address (rtnl_neigh_set_dst()) + * + * @par Changeable Attributes + * \anchor neigh_changeable + * - state (rtnl_neigh_set_state()) + * - link layer address (rtnl_neigh_set_lladdr()) + * + * @par Required Caches for Dumping + * In order to dump neighbour attributes you must provide the following + * caches via nl_cache_provide() + * - link cache holding all links + * + * @par TODO + * - Document proxy settings + * - Document states and their influence + * + * @par 1) Retrieving information about configured neighbours + * @code + * // The first step is to retrieve a list of all available neighbour within + * // the kernel and put them into a cache. + * struct nl_cache *cache = rtnl_neigh_alloc_cache(sk); + * + * // Neighbours can then be looked up by the interface and destination + * // address: + * struct rtnl_neigh *neigh = rtnl_neigh_get(cache, ifindex, dst_addr); + * + * // After successful usage, the object must be given back to the cache + * rtnl_neigh_put(neigh); + * @endcode + * + * @par 2) Adding new neighbours + * @code + * // Allocate an empty neighbour handle to be filled out with the attributes + * // of the new neighbour. + * struct rtnl_neigh *neigh = rtnl_neigh_alloc(); + * + * // Fill out the attributes of the new neighbour + * rtnl_neigh_set_ifindex(neigh, ifindex); + * rtnl_neigh_set_dst(neigh, dst_addr); + * rtnl_neigh_set_state(neigh, rtnl_neigh_str2state("permanent")); + * + * // Build the netlink message and send it to the kernel, the operation will + * // block until the operation has been completed. Alternatively the required + * // netlink message can be built using rtnl_neigh_build_add_request() + * // to be sent out using nl_send_auto_complete(). + * rtnl_neigh_add(sk, neigh, NLM_F_CREATE); + * + * // Free the memory + * rtnl_neigh_put(neigh); + * @endcode + * + * @par 3) Deleting an existing neighbour + * @code + * // Allocate an empty neighbour object to be filled out with the attributes + * // matching the neighbour to be deleted. Alternatively a fully equipped + * // neighbour object out of a cache can be used instead. + * struct rtnl_neigh *neigh = rtnl_neigh_alloc(); + * + * // Neighbours are uniquely identified by their interface index and + * // destination address, you may fill out other attributes but they + * // will have no influence. + * rtnl_neigh_set_ifindex(neigh, ifindex); + * rtnl_neigh_set_dst(neigh, dst_addr); + * + * // Build the netlink message and send it to the kernel, the operation will + * // block until the operation has been completed. Alternatively the required + * // netlink message can be built using rtnl_neigh_build_delete_request() + * // to be sent out using nl_send_auto_complete(). + * rtnl_neigh_delete(sk, neigh, 0); + * + * // Free the memory + * rtnl_neigh_put(neigh); + * @endcode + * + * @par 4) Changing neighbour attributes + * @code + * // Allocate an empty neighbour object to be filled out with the attributes + * // matching the neighbour to be changed and the new parameters. Alternatively + * // a fully equipped modified neighbour object out of a cache can be used. + * struct rtnl_neigh *neigh = rtnl_neigh_alloc(); + * + * // Identify the neighbour to be changed by its interface index and + * // destination address + * rtnl_neigh_set_ifindex(neigh, ifindex); + * rtnl_neigh_set_dst(neigh, dst_addr); + * + * // The link layer address may be modified, if so it is wise to change + * // its state to "permanent" in order to avoid having it overwritten. + * rtnl_neigh_set_lladdr(neigh, lladdr); + * + * // Secondly the state can be modified allowing normal neighbours to be + * // converted into permanent entries or to manually confirm a neighbour. + * rtnl_neigh_set_state(neigh, state); + * + * // Build the netlink message and send it to the kernel, the operation will + * // block until the operation has been completed. Alternatively the required + * // netlink message can be built using rtnl_neigh_build_change_request() + * // to be sent out using nl_send_auto_complete(). + * rtnl_neigh_add(sk, neigh, NLM_F_REPLACE); + * + * // Free the memory + * rtnl_neigh_put(neigh); + * @endcode + * @{ + */ + +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define NEIGH_ATTR_FLAGS 0x01 +#define NEIGH_ATTR_STATE 0x02 +#define NEIGH_ATTR_LLADDR 0x04 +#define NEIGH_ATTR_DST 0x08 +#define NEIGH_ATTR_CACHEINFO 0x10 +#define NEIGH_ATTR_IFINDEX 0x20 +#define NEIGH_ATTR_FAMILY 0x40 +#define NEIGH_ATTR_TYPE 0x80 +#define NEIGH_ATTR_PROBES 0x100 + +static struct nl_cache_ops rtnl_neigh_ops; +static struct nl_object_ops neigh_obj_ops; +/** @endcond */ + +static void neigh_free_data(struct nl_object *c) +{ + struct rtnl_neigh *neigh = nl_object_priv(c); + + if (!neigh) + return; + + nl_addr_put(neigh->n_lladdr); + nl_addr_put(neigh->n_dst); +} + +static int neigh_clone(struct nl_object *_dst, struct nl_object *_src) +{ + struct rtnl_neigh *dst = nl_object_priv(_dst); + struct rtnl_neigh *src = nl_object_priv(_src); + + if (src->n_lladdr) + if (!(dst->n_lladdr = nl_addr_clone(src->n_lladdr))) + return -NLE_NOMEM; + + if (src->n_dst) + if (!(dst->n_dst = nl_addr_clone(src->n_dst))) + return -NLE_NOMEM; + + return 0; +} + +static int neigh_compare(struct nl_object *_a, struct nl_object *_b, + uint32_t attrs, int flags) +{ + struct rtnl_neigh *a = (struct rtnl_neigh *) _a; + struct rtnl_neigh *b = (struct rtnl_neigh *) _b; + int diff = 0; + +#define NEIGH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NEIGH_ATTR_##ATTR, a, b, EXPR) + + diff |= NEIGH_DIFF(IFINDEX, a->n_ifindex != b->n_ifindex); + diff |= NEIGH_DIFF(FAMILY, a->n_family != b->n_family); + diff |= NEIGH_DIFF(TYPE, a->n_type != b->n_type); + diff |= NEIGH_DIFF(LLADDR, nl_addr_cmp(a->n_lladdr, b->n_lladdr)); + diff |= NEIGH_DIFF(DST, nl_addr_cmp(a->n_dst, b->n_dst)); + + if (flags & LOOSE_COMPARISON) { + diff |= NEIGH_DIFF(STATE, + (a->n_state ^ b->n_state) & b->n_state_mask); + diff |= NEIGH_DIFF(FLAGS, + (a->n_flags ^ b->n_flags) & b->n_flag_mask); + } else { + diff |= NEIGH_DIFF(STATE, a->n_state != b->n_state); + diff |= NEIGH_DIFF(FLAGS, a->n_flags != b->n_flags); + } + +#undef NEIGH_DIFF + + return diff; +} + +static const struct trans_tbl neigh_attrs[] = { + __ADD(NEIGH_ATTR_FLAGS, flags) + __ADD(NEIGH_ATTR_STATE, state) + __ADD(NEIGH_ATTR_LLADDR, lladdr) + __ADD(NEIGH_ATTR_DST, dst) + __ADD(NEIGH_ATTR_CACHEINFO, cacheinfo) + __ADD(NEIGH_ATTR_IFINDEX, ifindex) + __ADD(NEIGH_ATTR_FAMILY, family) + __ADD(NEIGH_ATTR_TYPE, type) + __ADD(NEIGH_ATTR_PROBES, probes) +}; + +static char *neigh_attrs2str(int attrs, char *buf, size_t len) +{ + return __flags2str(attrs, buf, len, neigh_attrs, + ARRAY_SIZE(neigh_attrs)); +} + +static struct nla_policy neigh_policy[NDA_MAX+1] = { + [NDA_CACHEINFO] = { .minlen = sizeof(struct nda_cacheinfo) }, + [NDA_PROBES] = { .type = NLA_U32 }, +}; + +static int neigh_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *n, struct nl_parser_param *pp) +{ + struct rtnl_neigh *neigh; + struct nlattr *tb[NDA_MAX + 1]; + struct ndmsg *nm; + int err; + + neigh = rtnl_neigh_alloc(); + if (!neigh) { + err = -NLE_NOMEM; + goto errout; + } + + neigh->ce_msgtype = n->nlmsg_type; + nm = nlmsg_data(n); + + err = nlmsg_parse(n, sizeof(*nm), tb, NDA_MAX, neigh_policy); + if (err < 0) + goto errout; + + neigh->n_family = nm->ndm_family; + neigh->n_ifindex = nm->ndm_ifindex; + neigh->n_state = nm->ndm_state; + neigh->n_flags = nm->ndm_flags; + neigh->n_type = nm->ndm_type; + + neigh->ce_mask |= (NEIGH_ATTR_FAMILY | NEIGH_ATTR_IFINDEX | + NEIGH_ATTR_STATE | NEIGH_ATTR_FLAGS | + NEIGH_ATTR_TYPE); + + if (tb[NDA_LLADDR]) { + neigh->n_lladdr = nl_addr_alloc_attr(tb[NDA_LLADDR], AF_UNSPEC); + if (!neigh->n_lladdr) { + err = -NLE_NOMEM; + goto errout; + } + nl_addr_set_family(neigh->n_lladdr, + nl_addr_guess_family(neigh->n_lladdr)); + neigh->ce_mask |= NEIGH_ATTR_LLADDR; + } + + if (tb[NDA_DST]) { + neigh->n_dst = nl_addr_alloc_attr(tb[NDA_DST], neigh->n_family); + if (!neigh->n_dst) { + err = -NLE_NOMEM; + goto errout; + } + neigh->ce_mask |= NEIGH_ATTR_DST; + } + + if (tb[NDA_CACHEINFO]) { + struct nda_cacheinfo *ci = nla_data(tb[NDA_CACHEINFO]); + + neigh->n_cacheinfo.nci_confirmed = ci->ndm_confirmed; + neigh->n_cacheinfo.nci_used = ci->ndm_used; + neigh->n_cacheinfo.nci_updated = ci->ndm_updated; + neigh->n_cacheinfo.nci_refcnt = ci->ndm_refcnt; + + neigh->ce_mask |= NEIGH_ATTR_CACHEINFO; + } + + if (tb[NDA_PROBES]) { + neigh->n_probes = nla_get_u32(tb[NDA_PROBES]); + neigh->ce_mask |= NEIGH_ATTR_PROBES; + } + + err = pp->pp_cb((struct nl_object *) neigh, pp); +errout: + rtnl_neigh_put(neigh); + return err; +} + +static int neigh_request_update(struct nl_cache *c, struct nl_sock *h) +{ + return nl_rtgen_request(h, RTM_GETNEIGH, AF_UNSPEC, NLM_F_DUMP); +} + + +static void neigh_dump_line(struct nl_object *a, struct nl_dump_params *p) +{ + char dst[INET6_ADDRSTRLEN+5], lladdr[INET6_ADDRSTRLEN+5]; + struct rtnl_neigh *n = (struct rtnl_neigh *) a; + struct nl_cache *link_cache; + char state[128], flags[64]; + + link_cache = nl_cache_mngt_require("route/link"); + + nl_dump_line(p, "%s ", nl_addr2str(n->n_dst, dst, sizeof(dst))); + + if (link_cache) + nl_dump(p, "dev %s ", + rtnl_link_i2name(link_cache, n->n_ifindex, + state, sizeof(state))); + else + nl_dump(p, "dev %d ", n->n_ifindex); + + if (n->ce_mask & NEIGH_ATTR_LLADDR) + nl_dump(p, "lladdr %s ", + nl_addr2str(n->n_lladdr, lladdr, sizeof(lladdr))); + + rtnl_neigh_state2str(n->n_state, state, sizeof(state)); + rtnl_neigh_flags2str(n->n_flags, flags, sizeof(flags)); + + if (state[0]) + nl_dump(p, "<%s", state); + if (flags[0]) + nl_dump(p, "%s%s", state[0] ? "," : "<", flags); + if (state[0] || flags[0]) + nl_dump(p, ">"); + nl_dump(p, "\n"); +} + +static void neigh_dump_details(struct nl_object *a, struct nl_dump_params *p) +{ + char rtn_type[32]; + struct rtnl_neigh *n = (struct rtnl_neigh *) a; + int hz = nl_get_user_hz(); + + neigh_dump_line(a, p); + + nl_dump_line(p, " refcnt %u type %s confirmed %u used " + "%u updated %u\n", + n->n_cacheinfo.nci_refcnt, + nl_rtntype2str(n->n_type, rtn_type, sizeof(rtn_type)), + n->n_cacheinfo.nci_confirmed/hz, + n->n_cacheinfo.nci_used/hz, n->n_cacheinfo.nci_updated/hz); +} + +static void neigh_dump_stats(struct nl_object *a, struct nl_dump_params *p) +{ + neigh_dump_details(a, p); +} + +/** + * @name Neighbour Object Allocation/Freeage + * @{ + */ + +struct rtnl_neigh *rtnl_neigh_alloc(void) +{ + return (struct rtnl_neigh *) nl_object_alloc(&neigh_obj_ops); +} + +void rtnl_neigh_put(struct rtnl_neigh *neigh) +{ + nl_object_put((struct nl_object *) neigh); +} + +/** @} */ + +/** + * @name Neighbour Cache Managament + * @{ + */ + +/** + * Build a neighbour cache including all neighbours currently configured in the kernel. + * @arg sock Netlink socket. + * @arg result Pointer to store resulting cache. + * + * Allocates a new neighbour cache, initializes it properly and updates it + * to include all neighbours currently configured in the kernel. + * + * @return 0 on success or a negative error code. + */ +int rtnl_neigh_alloc_cache(struct nl_sock *sock, struct nl_cache **result) +{ + return nl_cache_alloc_and_fill(&rtnl_neigh_ops, sock, result); +} + +/** + * Look up a neighbour by interface index and destination address + * @arg cache neighbour cache + * @arg ifindex interface index the neighbour is on + * @arg dst destination address of the neighbour + * @return neighbour handle or NULL if no match was found. + */ +struct rtnl_neigh * rtnl_neigh_get(struct nl_cache *cache, int ifindex, + struct nl_addr *dst) +{ + struct rtnl_neigh *neigh; + + nl_list_for_each_entry(neigh, &cache->c_items, ce_list) { + if (neigh->n_ifindex == ifindex && + !nl_addr_cmp(neigh->n_dst, dst)) { + nl_object_get((struct nl_object *) neigh); + return neigh; + } + } + + return NULL; +} + +/** @} */ + +/** + * @name Neighbour Addition + * @{ + */ + +static int build_neigh_msg(struct rtnl_neigh *tmpl, int cmd, int flags, + struct nl_msg **result) +{ + struct nl_msg *msg; + struct ndmsg nhdr = { + .ndm_ifindex = tmpl->n_ifindex, + .ndm_state = NUD_PERMANENT, + }; + + if (!(tmpl->ce_mask & NEIGH_ATTR_DST)) + return -NLE_MISSING_ATTR; + + nhdr.ndm_family = nl_addr_get_family(tmpl->n_dst); + + if (tmpl->ce_mask & NEIGH_ATTR_FLAGS) + nhdr.ndm_flags = tmpl->n_flags; + + if (tmpl->ce_mask & NEIGH_ATTR_STATE) + nhdr.ndm_state = tmpl->n_state; + + msg = nlmsg_alloc_simple(cmd, flags); + if (!msg) + return -NLE_NOMEM; + + if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + NLA_PUT_ADDR(msg, NDA_DST, tmpl->n_dst); + + if (tmpl->ce_mask & NEIGH_ATTR_LLADDR) + NLA_PUT_ADDR(msg, NDA_LLADDR, tmpl->n_lladdr); + + *result = msg; + return 0; + +nla_put_failure: + nlmsg_free(msg); + return -NLE_MSGSIZE; +} + +/** + * Build netlink request message to add a new neighbour + * @arg tmpl template with data of new neighbour + * @arg flags additional netlink message flags + * @arg result Pointer to store resulting message. + * + * Builds a new netlink message requesting a addition of a new + * neighbour. The netlink message header isn't fully equipped with + * all relevant fields and must thus be sent out via nl_send_auto_complete() + * or supplemented as needed. \a tmpl must contain the attributes of the new + * neighbour set via \c rtnl_neigh_set_* functions. + * + * The following attributes must be set in the template: + * - Interface index (rtnl_neigh_set_ifindex()) + * - State (rtnl_neigh_set_state()) + * - Destination address (rtnl_neigh_set_dst()) + * - Link layer address (rtnl_neigh_set_lladdr()) + * + * @return 0 on success or a negative error code. + */ +int rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags, + struct nl_msg **result) +{ + return build_neigh_msg(tmpl, RTM_NEWNEIGH, flags, result); +} + +/** + * Add a new neighbour + * @arg sk Netlink socket. + * @arg tmpl template with requested changes + * @arg flags additional netlink message flags + * + * Builds a netlink message by calling rtnl_neigh_build_add_request(), + * sends the request to the kernel and waits for the next ACK to be + * received and thus blocks until the request has been fullfilled. + * + * The following attributes must be set in the template: + * - Interface index (rtnl_neigh_set_ifindex()) + * - State (rtnl_neigh_set_state()) + * - Destination address (rtnl_neigh_set_dst()) + * - Link layer address (rtnl_neigh_set_lladdr()) + * + * @return 0 on sucess or a negative error if an error occured. + */ +int rtnl_neigh_add(struct nl_sock *sk, struct rtnl_neigh *tmpl, int flags) +{ + int err; + struct nl_msg *msg; + + if ((err = rtnl_neigh_build_add_request(tmpl, flags, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +/** @} */ + +/** + * @name Neighbour Deletion + * @{ + */ + +/** + * Build a netlink request message to delete a neighbour + * @arg neigh neighbour to delete + * @arg flags additional netlink message flags + * @arg result Pointer to store resulting message. + * + * Builds a new netlink message requesting a deletion of a neighbour. + * The netlink message header isn't fully equipped with all relevant + * fields and must thus be sent out via nl_send_auto_complete() + * or supplemented as needed. \a neigh must point to an existing + * neighbour. + * + * @return 0 on success or a negative error code. + */ +int rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh, int flags, + struct nl_msg **result) +{ + return build_neigh_msg(neigh, RTM_DELNEIGH, flags, result); +} + +/** + * Delete a neighbour + * @arg sk Netlink socket. + * @arg neigh neighbour to delete + * @arg flags additional netlink message flags + * + * Builds a netlink message by calling rtnl_neigh_build_delete_request(), + * sends the request to the kernel and waits for the next ACK to be + * received and thus blocks until the request has been fullfilled. + * + * @return 0 on sucess or a negative error if an error occured. + */ +int rtnl_neigh_delete(struct nl_sock *sk, struct rtnl_neigh *neigh, + int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_neigh_build_delete_request(neigh, flags, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +/** @} */ + +/** + * @name Neighbour States Translations + * @{ + */ + +static const struct trans_tbl neigh_states[] = { + __ADD(NUD_INCOMPLETE, incomplete) + __ADD(NUD_REACHABLE, reachable) + __ADD(NUD_STALE, stale) + __ADD(NUD_DELAY, delay) + __ADD(NUD_PROBE, probe) + __ADD(NUD_FAILED, failed) + __ADD(NUD_NOARP, norarp) + __ADD(NUD_PERMANENT, permanent) +}; + +char * rtnl_neigh_state2str(int state, char *buf, size_t len) +{ + return __flags2str(state, buf, len, neigh_states, + ARRAY_SIZE(neigh_states)); +} + +int rtnl_neigh_str2state(const char *name) +{ + return __str2type(name, neigh_states, ARRAY_SIZE(neigh_states)); +} + +/** @} */ + +/** + * @name Neighbour Flags Translations + * @{ + */ + +static const struct trans_tbl neigh_flags[] = { + __ADD(NTF_USE, use) + __ADD(NTF_PROXY, proxy) + __ADD(NTF_ROUTER, router) +}; + +char * rtnl_neigh_flags2str(int flags, char *buf, size_t len) +{ + return __flags2str(flags, buf, len, neigh_flags, + ARRAY_SIZE(neigh_flags)); +} + +int rtnl_neigh_str2flag(const char *name) +{ + return __str2type(name, neigh_flags, ARRAY_SIZE(neigh_flags)); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void rtnl_neigh_set_state(struct rtnl_neigh *neigh, int state) +{ + neigh->n_state_mask |= state; + neigh->n_state |= state; + neigh->ce_mask |= NEIGH_ATTR_STATE; +} + +int rtnl_neigh_get_state(struct rtnl_neigh *neigh) +{ + if (neigh->ce_mask & NEIGH_ATTR_STATE) + return neigh->n_state; + else + return -1; +} + +void rtnl_neigh_unset_state(struct rtnl_neigh *neigh, int state) +{ + neigh->n_state_mask |= state; + neigh->n_state &= ~state; + neigh->ce_mask |= NEIGH_ATTR_STATE; +} + +void rtnl_neigh_set_flags(struct rtnl_neigh *neigh, unsigned int flags) +{ + neigh->n_flag_mask |= flags; + neigh->n_flags |= flags; + neigh->ce_mask |= NEIGH_ATTR_FLAGS; +} + +unsigned int rtnl_neigh_get_flags(struct rtnl_neigh *neigh) +{ + return neigh->n_flags; +} + +void rtnl_neigh_unset_flags(struct rtnl_neigh *neigh, unsigned int flags) +{ + neigh->n_flag_mask |= flags; + neigh->n_flags &= ~flags; + neigh->ce_mask |= NEIGH_ATTR_FLAGS; +} + +void rtnl_neigh_set_ifindex(struct rtnl_neigh *neigh, int ifindex) +{ + neigh->n_ifindex = ifindex; + neigh->ce_mask |= NEIGH_ATTR_IFINDEX; +} + +int rtnl_neigh_get_ifindex(struct rtnl_neigh *neigh) +{ + return neigh->n_ifindex; +} + +static inline int __assign_addr(struct rtnl_neigh *neigh, struct nl_addr **pos, + struct nl_addr *new, int flag, int nocheck) +{ + if (!nocheck) { + if (neigh->ce_mask & NEIGH_ATTR_FAMILY) { + if (new->a_family != neigh->n_family) + return -NLE_AF_MISMATCH; + } else { + neigh->n_family = new->a_family; + neigh->ce_mask |= NEIGH_ATTR_FAMILY; + } + } + + if (*pos) + nl_addr_put(*pos); + + nl_addr_get(new); + *pos = new; + + neigh->ce_mask |= flag; + + return 0; +} + +void rtnl_neigh_set_lladdr(struct rtnl_neigh *neigh, struct nl_addr *addr) +{ + __assign_addr(neigh, &neigh->n_lladdr, addr, NEIGH_ATTR_LLADDR, 1); +} + +struct nl_addr *rtnl_neigh_get_lladdr(struct rtnl_neigh *neigh) +{ + if (neigh->ce_mask & NEIGH_ATTR_LLADDR) + return neigh->n_lladdr; + else + return NULL; +} + +int rtnl_neigh_set_dst(struct rtnl_neigh *neigh, struct nl_addr *addr) +{ + return __assign_addr(neigh, &neigh->n_dst, addr, + NEIGH_ATTR_DST, 0); +} + +struct nl_addr *rtnl_neigh_get_dst(struct rtnl_neigh *neigh) +{ + if (neigh->ce_mask & NEIGH_ATTR_DST) + return neigh->n_dst; + else + return NULL; +} + +void rtnl_neigh_set_family(struct rtnl_neigh *neigh, int family) +{ + neigh->n_family = family; + neigh->ce_mask |= NEIGH_ATTR_FAMILY; +} + +int rtnl_neigh_get_family(struct rtnl_neigh *neigh) +{ + return neigh->n_family; +} + +void rtnl_neigh_set_type(struct rtnl_neigh *neigh, int type) +{ + neigh->n_type = type; + neigh->ce_mask = NEIGH_ATTR_TYPE; +} + +int rtnl_neigh_get_type(struct rtnl_neigh *neigh) +{ + if (neigh->ce_mask & NEIGH_ATTR_TYPE) + return neigh->n_type; + else + return -1; +} + +/** @} */ + +static struct nl_object_ops neigh_obj_ops = { + .oo_name = "route/neigh", + .oo_size = sizeof(struct rtnl_neigh), + .oo_free_data = neigh_free_data, + .oo_clone = neigh_clone, + .oo_dump = { + [NL_DUMP_LINE] = neigh_dump_line, + [NL_DUMP_DETAILS] = neigh_dump_details, + [NL_DUMP_STATS] = neigh_dump_stats, + }, + .oo_compare = neigh_compare, + .oo_attrs2str = neigh_attrs2str, + .oo_id_attrs = (NEIGH_ATTR_IFINDEX | NEIGH_ATTR_DST | NEIGH_ATTR_FAMILY), +}; + +static struct nl_af_group neigh_groups[] = { + { AF_UNSPEC, RTNLGRP_NEIGH }, + { END_OF_GROUP_LIST }, +}; + +static struct nl_cache_ops rtnl_neigh_ops = { + .co_name = "route/neigh", + .co_hdrsize = sizeof(struct ndmsg), + .co_msgtypes = { + { RTM_NEWNEIGH, NL_ACT_NEW, "new" }, + { RTM_DELNEIGH, NL_ACT_DEL, "del" }, + { RTM_GETNEIGH, NL_ACT_GET, "get" }, + END_OF_MSGTYPES_LIST, + }, + .co_protocol = NETLINK_ROUTE, + .co_groups = neigh_groups, + .co_request_update = neigh_request_update, + .co_msg_parser = neigh_msg_parser, + .co_obj_ops = &neigh_obj_ops, +}; + +static void __init neigh_init(void) +{ + nl_cache_mngt_register(&rtnl_neigh_ops); +} + +static void __exit neigh_exit(void) +{ + nl_cache_mngt_unregister(&rtnl_neigh_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/neightbl.c b/libnetwork/libnl3/lib/route/neightbl.c new file mode 100644 index 0000000..9599faa --- /dev/null +++ b/libnetwork/libnl3/lib/route/neightbl.c @@ -0,0 +1,815 @@ +/* + * lib/route/neightbl.c neighbour tables + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup rtnl + * @defgroup neightbl Neighbour Tables + * @brief + * @{ + */ + +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define NEIGHTBL_ATTR_FAMILY 0x001 +#define NEIGHTBL_ATTR_STATS 0x002 +#define NEIGHTBL_ATTR_NAME 0x004 +#define NEIGHTBL_ATTR_THRESH1 0x008 +#define NEIGHTBL_ATTR_THRESH2 0x010 +#define NEIGHTBL_ATTR_THRESH3 0x020 +#define NEIGHTBL_ATTR_CONFIG 0x040 +#define NEIGHTBL_ATTR_PARMS 0x080 +#define NEIGHTBL_ATTR_GC_INTERVAL 0x100 + +#define NEIGHTBLPARM_ATTR_IFINDEX 0x0001 +#define NEIGHTBLPARM_ATTR_REFCNT 0x0002 +#define NEIGHTBLPARM_ATTR_QUEUE_LEN 0x0004 +#define NEIGHTBLPARM_ATTR_APP_PROBES 0x0008 +#define NEIGHTBLPARM_ATTR_UCAST_PROBES 0x0010 +#define NEIGHTBLPARM_ATTR_MCAST_PROBES 0x0020 +#define NEIGHTBLPARM_ATTR_PROXY_QLEN 0x0040 +#define NEIGHTBLPARM_ATTR_REACHABLE_TIME 0x0080 +#define NEIGHTBLPARM_ATTR_BASE_REACHABLE_TIME 0x0100 +#define NEIGHTBLPARM_ATTR_RETRANS_TIME 0x0200 +#define NEIGHTBLPARM_ATTR_GC_STALETIME 0x0400 +#define NEIGHTBLPARM_ATTR_DELAY_PROBE_TIME 0x0800 +#define NEIGHTBLPARM_ATTR_ANYCAST_DELAY 0x1000 +#define NEIGHTBLPARM_ATTR_PROXY_DELAY 0x2000 +#define NEIGHTBLPARM_ATTR_LOCKTIME 0x4000 + +static struct nl_cache_ops rtnl_neightbl_ops; +static struct nl_object_ops neightbl_obj_ops; +/** @endcond */ + +static int neightbl_compare(struct nl_object *_a, struct nl_object *_b, + uint32_t attrs, int flags) +{ + struct rtnl_neightbl *a = (struct rtnl_neightbl *) _a; + struct rtnl_neightbl *b = (struct rtnl_neightbl *) _b; + int diff = 0; + +#define NT_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NEIGHTBL_ATTR_##ATTR, a, b, EXPR) + + diff |= NT_DIFF(FAMILY, a->nt_family != b->nt_family); + diff |= NT_DIFF(NAME, strcmp(a->nt_name, b->nt_name)); + diff |= NT_DIFF(THRESH1, a->nt_gc_thresh1 != b->nt_gc_thresh1); + diff |= NT_DIFF(THRESH2, a->nt_gc_thresh2 != b->nt_gc_thresh2); + diff |= NT_DIFF(THRESH3, a->nt_gc_thresh3 != b->nt_gc_thresh3); + diff |= NT_DIFF(GC_INTERVAL, a->nt_gc_interval != b->nt_gc_interval); + +#undef NT_DIFF + + if (!(a->ce_mask & NEIGHTBL_ATTR_PARMS) && + !(b->ce_mask & NEIGHTBL_ATTR_PARMS)) + return diff; + + /* XXX: FIXME: Compare parameter table */ + + +#if 0 +#define REQ(F) (fp->ntp_mask & NEIGHTBLPARM_ATTR_##F) +#define AVAIL(F) (op->ntp_mask & NEIGHTBLPARM_ATTR_##F) +#define _C(F, N) (REQ(F) && (!AVAIL(F) || (op->N != fp->N))) + if (_C(IFINDEX, ntp_ifindex) || + _C(QUEUE_LEN, ntp_queue_len) || + _C(APP_PROBES, ntp_app_probes) || + _C(UCAST_PROBES, ntp_ucast_probes) || + _C(MCAST_PROBES, ntp_mcast_probes) || + _C(PROXY_QLEN, ntp_proxy_qlen) || + _C(LOCKTIME, ntp_locktime) || + _C(RETRANS_TIME, ntp_retrans_time) || + _C(BASE_REACHABLE_TIME, ntp_base_reachable_time) || + _C(GC_STALETIME, ntp_gc_stale_time) || + _C(DELAY_PROBE_TIME, ntp_probe_delay) || + _C(ANYCAST_DELAY, ntp_anycast_delay) || + _C(PROXY_DELAY, ntp_proxy_delay)) + return 0; +#undef REQ +#undef AVAIL +#undef _C +#endif + + return diff; +} + + +static struct nla_policy neightbl_policy[NDTA_MAX+1] = { + [NDTA_NAME] = { .type = NLA_STRING, + .maxlen = NTBLNAMSIZ }, + [NDTA_THRESH1] = { .type = NLA_U32 }, + [NDTA_THRESH2] = { .type = NLA_U32 }, + [NDTA_THRESH3] = { .type = NLA_U32 }, + [NDTA_GC_INTERVAL] = { .type = NLA_U32 }, + [NDTA_CONFIG] = { .minlen = sizeof(struct ndt_config) }, + [NDTA_STATS] = { .minlen = sizeof(struct ndt_stats) }, + [NDTA_PARMS] = { .type = NLA_NESTED }, +}; + +static int neightbl_msg_parser(struct nl_cache_ops *ops, + struct sockaddr_nl *who, struct nlmsghdr *n, + struct nl_parser_param *pp) +{ + struct rtnl_neightbl *ntbl; + struct nlattr *tb[NDTA_MAX + 1]; + struct rtgenmsg *rtmsg; + int err; + + ntbl = rtnl_neightbl_alloc(); + if (!ntbl) { + err = -NLE_NOMEM; + goto errout; + } + + ntbl->ce_msgtype = n->nlmsg_type; + rtmsg = nlmsg_data(n); + + err = nlmsg_parse(n, sizeof(*rtmsg), tb, NDTA_MAX, neightbl_policy); + if (err < 0) + goto errout; + + ntbl->nt_family = rtmsg->rtgen_family; + + if (tb[NDTA_NAME] == NULL) { + return -NLE_MISSING_ATTR; + goto errout; + } + + nla_strlcpy(ntbl->nt_name, tb[NDTA_NAME], NTBLNAMSIZ); + ntbl->ce_mask |= NEIGHTBL_ATTR_NAME; + + if (tb[NDTA_THRESH1]) { + ntbl->nt_gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]); + ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH1; + } + + if (tb[NDTA_THRESH2]) { + ntbl->nt_gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]); + ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH2; + } + + if (tb[NDTA_THRESH3]) { + ntbl->nt_gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]); + ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH3; + } + + if (tb[NDTA_GC_INTERVAL]) { + ntbl->nt_gc_interval = nla_get_u32(tb[NDTA_GC_INTERVAL]); + ntbl->ce_mask |= NEIGHTBL_ATTR_GC_INTERVAL; + } + + if (tb[NDTA_CONFIG]) { + nla_memcpy(&ntbl->nt_config, tb[NDTA_CONFIG], + sizeof(ntbl->nt_config)); + ntbl->ce_mask |= NEIGHTBL_ATTR_CONFIG; + } + + if (tb[NDTA_STATS]) { + nla_memcpy(&ntbl->nt_stats, tb[NDTA_STATS], + sizeof(ntbl->nt_stats)); + ntbl->ce_mask |= NEIGHTBL_ATTR_STATS; + } + + if (tb[NDTA_PARMS]) { + struct nlattr *tbp[NDTPA_MAX + 1]; + struct rtnl_neightbl_parms *p = &ntbl->nt_parms; + + err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS], NULL); + if (err < 0) + goto errout; + +#define COPY_ENTRY(name, var) \ + if (tbp[NDTPA_ ##name]) { \ + p->ntp_ ##var = nla_get_u32(tbp[NDTPA_ ##name]); \ + p->ntp_mask |= NEIGHTBLPARM_ATTR_ ##name; \ + } + + COPY_ENTRY(IFINDEX, ifindex); + COPY_ENTRY(REFCNT, refcnt); + COPY_ENTRY(QUEUE_LEN, queue_len); + COPY_ENTRY(APP_PROBES, app_probes); + COPY_ENTRY(UCAST_PROBES, ucast_probes); + COPY_ENTRY(MCAST_PROBES, mcast_probes); + COPY_ENTRY(PROXY_QLEN, proxy_qlen); + COPY_ENTRY(PROXY_DELAY, proxy_delay); + COPY_ENTRY(ANYCAST_DELAY, anycast_delay); + COPY_ENTRY(LOCKTIME, locktime); + COPY_ENTRY(REACHABLE_TIME, reachable_time); + COPY_ENTRY(BASE_REACHABLE_TIME, base_reachable_time); + COPY_ENTRY(RETRANS_TIME, retrans_time); + COPY_ENTRY(GC_STALETIME, gc_stale_time); + COPY_ENTRY(DELAY_PROBE_TIME, probe_delay); +#undef COPY_ENTRY + + ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS; + } + + err = pp->pp_cb((struct nl_object *) ntbl, pp); +errout: + rtnl_neightbl_put(ntbl); + return err; +} + +static int neightbl_request_update(struct nl_cache *c, struct nl_sock *h) +{ + return nl_rtgen_request(h, RTM_GETNEIGHTBL, AF_UNSPEC, NLM_F_DUMP); +} + + +static void neightbl_dump_line(struct nl_object *arg, struct nl_dump_params *p) +{ + struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg; + + nl_dump_line(p, "%s", ntbl->nt_name); + + if (ntbl->nt_parms.ntp_mask & NEIGHTBLPARM_ATTR_IFINDEX) { + struct nl_cache *link_cache; + + link_cache = nl_cache_mngt_require("route/link"); + + if (link_cache) { + char buf[32]; + nl_dump(p, "<%s> ", + rtnl_link_i2name(link_cache, + ntbl->nt_parms.ntp_ifindex, + buf, sizeof(buf))); + } else + nl_dump(p, "<%u> ", ntbl->nt_parms.ntp_ifindex); + } else + nl_dump(p, " "); + + if (ntbl->ce_mask & NEIGHTBL_ATTR_CONFIG) + nl_dump(p, "entries %u ", ntbl->nt_config.ndtc_entries); + + if (ntbl->ce_mask & NEIGHTBL_ATTR_PARMS) { + char rt[32], rt2[32]; + struct rtnl_neightbl_parms *pa = &ntbl->nt_parms; + + nl_dump(p, "reachable-time %s retransmit-time %s", + nl_msec2str(pa->ntp_reachable_time, rt, sizeof(rt)), + nl_msec2str(pa->ntp_retrans_time, rt2, sizeof(rt2))); + } + + nl_dump(p, "\n"); +} + +static void neightbl_dump_details(struct nl_object *arg, struct nl_dump_params *p) +{ + char x[32], y[32], z[32]; + struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg; + + neightbl_dump_line(arg, p); + + if (ntbl->ce_mask & NEIGHTBL_ATTR_CONFIG) { + nl_dump_line(p, " key-len %u entry-size %u last-flush %s\n", + ntbl->nt_config.ndtc_key_len, + ntbl->nt_config.ndtc_entry_size, + nl_msec2str(ntbl->nt_config.ndtc_last_flush, + x, sizeof(x))); + + nl_dump_line(p, " gc threshold %u/%u/%u interval %s " \ + "chain-position %u\n", + ntbl->nt_gc_thresh1, ntbl->nt_gc_thresh2, + ntbl->nt_gc_thresh3, + nl_msec2str(ntbl->nt_gc_interval, x, sizeof(x)), + ntbl->nt_config.ndtc_hash_chain_gc); + + nl_dump_line(p, " hash-rand 0x%08X/0x%08X last-rand %s\n", + ntbl->nt_config.ndtc_hash_rnd, + ntbl->nt_config.ndtc_hash_mask, + nl_msec2str(ntbl->nt_config.ndtc_last_rand, + x, sizeof(x))); + } + + if (ntbl->ce_mask & NEIGHTBL_ATTR_PARMS) { + struct rtnl_neightbl_parms *pa = &ntbl->nt_parms; + + nl_dump_line(p, " refcnt %u pending-queue-limit %u " \ + "proxy-delayed-queue-limit %u\n", + pa->ntp_refcnt, + pa->ntp_queue_len, + pa->ntp_proxy_qlen); + + nl_dump_line(p, " num-userspace-probes %u num-unicast-probes " \ + "%u num-multicast-probes %u\n", + pa->ntp_app_probes, + pa->ntp_ucast_probes, + pa->ntp_mcast_probes); + + nl_dump_line(p, " min-age %s base-reachable-time %s " \ + "stale-check-interval %s\n", + nl_msec2str(pa->ntp_locktime, x, sizeof(x)), + nl_msec2str(pa->ntp_base_reachable_time, + y, sizeof(y)), + nl_msec2str(pa->ntp_gc_stale_time, z, sizeof(z))); + + nl_dump_line(p, " initial-probe-delay %s answer-delay %s " \ + "proxy-answer-delay %s\n", + nl_msec2str(pa->ntp_probe_delay, x, sizeof(x)), + nl_msec2str(pa->ntp_anycast_delay, y, sizeof(y)), + nl_msec2str(pa->ntp_proxy_delay, z, sizeof(z))); + } +} + +static void neightbl_dump_stats(struct nl_object *arg, struct nl_dump_params *p) +{ + struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg; + + neightbl_dump_details(arg, p); + + if (!(ntbl->ce_mask & NEIGHTBL_ATTR_STATS)) + return; + + nl_dump_line(p, " lookups %lld hits %lld failed %lld " \ + "allocations %lld destroys %lld\n", + ntbl->nt_stats.ndts_lookups, + ntbl->nt_stats.ndts_hits, + ntbl->nt_stats.ndts_res_failed, + ntbl->nt_stats.ndts_allocs, + ntbl->nt_stats.ndts_destroys); + + nl_dump_line(p, " hash-grows %lld forced-gc-runs %lld " \ + "periodic-gc-runs %lld\n", + ntbl->nt_stats.ndts_hash_grows, + ntbl->nt_stats.ndts_forced_gc_runs, + ntbl->nt_stats.ndts_periodic_gc_runs); + + nl_dump_line(p, " rcv-unicast-probes %lld rcv-multicast-probes %lld\n", + ntbl->nt_stats.ndts_rcv_probes_ucast, + ntbl->nt_stats.ndts_rcv_probes_mcast); +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct rtnl_neightbl *rtnl_neightbl_alloc(void) +{ + return (struct rtnl_neightbl *) nl_object_alloc(&neightbl_obj_ops); +} + +void rtnl_neightbl_put(struct rtnl_neightbl *neightbl) +{ + nl_object_put((struct nl_object *) neightbl); +} + +/** @} */ + +/** + * @name Neighbour Table Cache Management + * @{ + */ + +/** + * Build a neighbour table cache including all neighbour tables currently configured in the kernel. + * @arg sk Netlink socket. + * @arg result Pointer to store resulting cache. + * + * Allocates a new neighbour table cache, initializes it properly and + * updates it to include all neighbour tables currently configured in + * the kernel. + * + * @return 0 on success or a negative error code. + */ +int rtnl_neightbl_alloc_cache(struct nl_sock *sk, struct nl_cache **result) +{ + return nl_cache_alloc_and_fill(&rtnl_neightbl_ops, sk, result); +} + +/** + * Lookup neighbour table by name and optional interface index + * @arg cache neighbour table cache + * @arg name name of table + * @arg ifindex optional interface index + * + * Looks up the neighbour table matching the specified name and + * optionally the specified ifindex to retrieve device specific + * parameter sets. + * + * @return ptr to neighbour table inside the cache or NULL if no + * match was found. + */ +struct rtnl_neightbl *rtnl_neightbl_get(struct nl_cache *cache, + const char *name, int ifindex) +{ + struct rtnl_neightbl *nt; + + if (cache->c_ops != &rtnl_neightbl_ops) + return NULL; + + nl_list_for_each_entry(nt, &cache->c_items, ce_list) { + if (!strcasecmp(nt->nt_name, name) && + ((!ifindex && !nt->nt_parms.ntp_ifindex) || + (ifindex && ifindex == nt->nt_parms.ntp_ifindex))) { + nl_object_get((struct nl_object *) nt); + return nt; + } + } + + return NULL; +} + +/** @} */ + +/** + * @name Neighbour Table Modifications + * @{ + */ + +/** + * Builds a netlink change request message to change neighbour table attributes + * @arg old neighbour table to change + * @arg tmpl template with requested changes + * @arg result Pointer to store resulting message. + * + * Builds a new netlink message requesting a change of neighbour table + * attributes. The netlink message header isn't fully equipped with all + * relevant fields and must be sent out via nl_send_auto_complete() or + * supplemented as needed. + * \a old must point to a neighbour table currently configured in the + * kernel and \a tmpl must contain the attributes to be changed set via + * \c rtnl_neightbl_set_* functions. + * + * @return 0 on success or a negative error code. + */ +int rtnl_neightbl_build_change_request(struct rtnl_neightbl *old, + struct rtnl_neightbl *tmpl, + struct nl_msg **result) +{ + struct nl_msg *m, *parms = NULL; + struct ndtmsg ndt = { + .ndtm_family = old->nt_family, + }; + + m = nlmsg_alloc_simple(RTM_SETNEIGHTBL, 0); + if (!m) + return -NLE_NOMEM; + + if (nlmsg_append(m, &ndt, sizeof(ndt), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + NLA_PUT_STRING(m, NDTA_NAME, old->nt_name); + + if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH1) + NLA_PUT_U32(m, NDTA_THRESH1, tmpl->nt_gc_thresh1); + + if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH2) + NLA_PUT_U32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2); + + if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH2) + NLA_PUT_U32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2); + + if (tmpl->ce_mask & NEIGHTBL_ATTR_GC_INTERVAL) + NLA_PUT_U64(m, NDTA_GC_INTERVAL, + tmpl->nt_gc_interval); + + if (tmpl->ce_mask & NEIGHTBL_ATTR_PARMS) { + struct rtnl_neightbl_parms *p = &tmpl->nt_parms; + + parms = nlmsg_alloc(); + if (!parms) + goto nla_put_failure; + + if (old->nt_parms.ntp_mask & NEIGHTBLPARM_ATTR_IFINDEX) + NLA_PUT_U32(parms, NDTPA_IFINDEX, + old->nt_parms.ntp_ifindex); + + + if (p->ntp_mask & NEIGHTBLPARM_ATTR_QUEUE_LEN) + NLA_PUT_U32(parms, NDTPA_QUEUE_LEN, p->ntp_queue_len); + + if (p->ntp_mask & NEIGHTBLPARM_ATTR_APP_PROBES) + NLA_PUT_U32(parms, NDTPA_APP_PROBES, p->ntp_app_probes); + + if (p->ntp_mask & NEIGHTBLPARM_ATTR_UCAST_PROBES) + NLA_PUT_U32(parms, NDTPA_UCAST_PROBES, + p->ntp_ucast_probes); + + if (p->ntp_mask & NEIGHTBLPARM_ATTR_MCAST_PROBES) + NLA_PUT_U32(parms, NDTPA_MCAST_PROBES, + p->ntp_mcast_probes); + + if (p->ntp_mask & NEIGHTBLPARM_ATTR_PROXY_QLEN) + NLA_PUT_U32(parms, NDTPA_PROXY_QLEN, + p->ntp_proxy_qlen); + + if (p->ntp_mask & NEIGHTBLPARM_ATTR_BASE_REACHABLE_TIME) + NLA_PUT_U64(parms, NDTPA_BASE_REACHABLE_TIME, + p->ntp_base_reachable_time); + + if (p->ntp_mask & NEIGHTBLPARM_ATTR_RETRANS_TIME) + NLA_PUT_U64(parms, NDTPA_RETRANS_TIME, + p->ntp_retrans_time); + + if (p->ntp_mask & NEIGHTBLPARM_ATTR_GC_STALETIME) + NLA_PUT_U64(parms, NDTPA_GC_STALETIME, + p->ntp_gc_stale_time); + + if (p->ntp_mask & NEIGHTBLPARM_ATTR_DELAY_PROBE_TIME) + NLA_PUT_U64(parms, NDTPA_DELAY_PROBE_TIME, + p->ntp_proxy_delay); + + if (p->ntp_mask & NEIGHTBLPARM_ATTR_ANYCAST_DELAY) + NLA_PUT_U64(parms, NDTPA_ANYCAST_DELAY, + p->ntp_anycast_delay); + + if (p->ntp_mask & NEIGHTBLPARM_ATTR_PROXY_DELAY) + NLA_PUT_U64(parms, NDTPA_PROXY_DELAY, + p->ntp_proxy_delay); + + if (p->ntp_mask & NEIGHTBLPARM_ATTR_LOCKTIME) + NLA_PUT_U64(parms, NDTPA_LOCKTIME, p->ntp_locktime); + + if (nla_put_nested(m, NDTA_PARMS, parms) < 0) + goto nla_put_failure; + + nlmsg_free(parms); + } + + *result = m; + return 0; + +nla_put_failure: + if (parms) + nlmsg_free(parms); + nlmsg_free(m); + return -NLE_MSGSIZE; +} + +/** + * Change neighbour table attributes + * @arg sk Netlink socket. + * @arg old neighbour table to be changed + * @arg tmpl template with requested changes + * + * Builds a new netlink message by calling + * rtnl_neightbl_build_change_request(), sends the request to the + * kernel and waits for the next ACK to be received, i.e. blocks + * until the request has been processed. + * + * @return 0 on success or a negative error code + */ +int rtnl_neightbl_change(struct nl_sock *sk, struct rtnl_neightbl *old, + struct rtnl_neightbl *tmpl) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_neightbl_build_change_request(old, tmpl, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +/** @} */ + +/** + * @name Attribute Modification + * @{ + */ + +void rtnl_neightbl_set_family(struct rtnl_neightbl *ntbl, int family) +{ + ntbl->nt_family = family; + ntbl->ce_mask |= NEIGHTBL_ATTR_FAMILY; +} + +void rtnl_neightbl_set_gc_interval(struct rtnl_neightbl *ntbl, uint64_t ms) +{ + ntbl->nt_gc_interval = ms; + ntbl->ce_mask |= NEIGHTBL_ATTR_GC_INTERVAL; +} + +void rtnl_neightbl_set_gc_tresh1(struct rtnl_neightbl *ntbl, int thresh) +{ + ntbl->nt_gc_thresh1 = thresh; + ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH1; +} + +void rtnl_neightbl_set_gc_tresh2(struct rtnl_neightbl *ntbl, int thresh) +{ + ntbl->nt_gc_thresh2 = thresh; + ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH2; +} + +void rtnl_neightbl_set_gc_tresh3(struct rtnl_neightbl *ntbl, int thresh) +{ + ntbl->nt_gc_thresh3 = thresh; + ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH3; +} + +void rtnl_neightbl_set_name(struct rtnl_neightbl *ntbl, const char *name) +{ + strncpy(ntbl->nt_name, name, sizeof(ntbl->nt_name) - 1); + ntbl->ce_mask |= NEIGHTBL_ATTR_NAME; +} + +void rtnl_neightbl_set_dev(struct rtnl_neightbl *ntbl, int ifindex) +{ + ntbl->nt_parms.ntp_ifindex = ifindex; + ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_IFINDEX; + ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS; +} + +/** + * Set the queue length for pending requests of a neighbour table to the specified value + * @arg ntbl neighbour table to change + * @arg len new queue len + */ +void rtnl_neightbl_set_queue_len(struct rtnl_neightbl *ntbl, int len) +{ + ntbl->nt_parms.ntp_queue_len = len; + ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_QUEUE_LEN; + ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS; +} + +/** + * Set the queue length for delay proxy arp requests of a neighbour table to the specified value + * @arg ntbl neighbour table to change + * @arg len new queue len + */ +void rtnl_neightbl_set_proxy_queue_len(struct rtnl_neightbl *ntbl, int len) +{ + ntbl->nt_parms.ntp_proxy_qlen = len; + ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_PROXY_QLEN; + ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS; +} + +/** + * Set the number of application probes of a neighbour table to the specified value + * @arg ntbl neighbour table to change + * @arg probes new probes value + */ +void rtnl_neightbl_set_app_probes(struct rtnl_neightbl *ntbl, int probes) +{ + ntbl->nt_parms.ntp_app_probes = probes; + ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_APP_PROBES; + ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS; +} + +/** + * Set the number of unicast probes of a neighbour table to the specified value + * @arg ntbl neighbour table to change + * @arg probes new probes value + */ +void rtnl_neightbl_set_ucast_probes(struct rtnl_neightbl *ntbl, int probes) +{ + ntbl->nt_parms.ntp_ucast_probes = probes; + ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_UCAST_PROBES; + ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS; +} + +/** + * Set the number of multicast probes of a neighbour table to the specified value + * @arg ntbl neighbour table to change + * @arg probes new probes value + */ +void rtnl_neightbl_set_mcast_probes(struct rtnl_neightbl *ntbl, int probes) +{ + ntbl->nt_parms.ntp_mcast_probes = probes; + ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_MCAST_PROBES; + ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS; +} + +/** + * Set the base reachable time of a neighbour table to the specified value + * @arg ntbl neighbour table to change + * @arg ms new base reachable time in milliseconds + */ +void rtnl_neightbl_set_base_reachable_time(struct rtnl_neightbl *ntbl, + uint64_t ms) +{ + ntbl->nt_parms.ntp_base_reachable_time = ms; + ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_BASE_REACHABLE_TIME; + ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS; +} + +/** + * Set the retransmit time of a neighbour table to the specified value + * @arg ntbl neighbour table to change + * @arg ms new retransmit time + */ +void rtnl_neightbl_set_retrans_time(struct rtnl_neightbl *ntbl, uint64_t ms) +{ + ntbl->nt_parms.ntp_retrans_time = ms; + ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_RETRANS_TIME; + ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS; +} + +/** + * Set the gc stale time of a neighbour table to the specified value + * @arg ntbl neighbour table to change + * @arg ms new gc stale time in milliseconds + */ +void rtnl_neightbl_set_gc_stale_time(struct rtnl_neightbl *ntbl, uint64_t ms) +{ + ntbl->nt_parms.ntp_gc_stale_time = ms; + ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_GC_STALETIME; + ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS; +} + +/** + * Set the first probe delay time of a neighbour table to the specified value + * @arg ntbl neighbour table to change + * @arg ms new first probe delay time in milliseconds + */ +void rtnl_neightbl_set_delay_probe_time(struct rtnl_neightbl *ntbl, uint64_t ms) +{ + ntbl->nt_parms.ntp_probe_delay = ms; + ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_DELAY_PROBE_TIME; + ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS; +} + +/** + * Set the anycast delay of a neighbour table to the specified value + * @arg ntbl neighbour table to change + * @arg ms new anycast delay in milliseconds + */ +void rtnl_neightbl_set_anycast_delay(struct rtnl_neightbl *ntbl, uint64_t ms) +{ + ntbl->nt_parms.ntp_anycast_delay = ms; + ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_ANYCAST_DELAY; + ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS; +} + +/** + * Set the proxy delay of a neighbour table to the specified value + * @arg ntbl neighbour table to change + * @arg ms new proxy delay in milliseconds + */ +void rtnl_neightbl_set_proxy_delay(struct rtnl_neightbl *ntbl, uint64_t ms) +{ + ntbl->nt_parms.ntp_proxy_delay = ms; + ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_PROXY_DELAY; + ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS; +} + +/** + * Set the locktime of a neighbour table to the specified value + * @arg ntbl neighbour table to change + * @arg ms new locktime in milliseconds + */ +void rtnl_neightbl_set_locktime(struct rtnl_neightbl *ntbl, uint64_t ms) +{ + ntbl->nt_parms.ntp_locktime = ms; + ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_LOCKTIME; + ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS; +} + +/** @} */ + +static struct nl_object_ops neightbl_obj_ops = { + .oo_name = "route/neightbl", + .oo_size = sizeof(struct rtnl_neightbl), + .oo_dump = { + [NL_DUMP_LINE] = neightbl_dump_line, + [NL_DUMP_DETAILS] = neightbl_dump_details, + [NL_DUMP_STATS] = neightbl_dump_stats, + }, + .oo_compare = neightbl_compare, +}; + +static struct nl_cache_ops rtnl_neightbl_ops = { + .co_name = "route/neightbl", + .co_hdrsize = sizeof(struct rtgenmsg), + .co_msgtypes = { + { RTM_NEWNEIGHTBL, NL_ACT_NEW, "new" }, + { RTM_SETNEIGHTBL, NL_ACT_SET, "set" }, + { RTM_GETNEIGHTBL, NL_ACT_GET, "get" }, + END_OF_MSGTYPES_LIST, + }, + .co_protocol = NETLINK_ROUTE, + .co_request_update = neightbl_request_update, + .co_msg_parser = neightbl_msg_parser, + .co_obj_ops = &neightbl_obj_ops, +}; + +static void __init neightbl_init(void) +{ + nl_cache_mngt_register(&rtnl_neightbl_ops); +} + +static void __exit neightbl_exit(void) +{ + nl_cache_mngt_unregister(&rtnl_neightbl_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/nexthop.c b/libnetwork/libnl3/lib/route/nexthop.c new file mode 100644 index 0000000..48cbfcf --- /dev/null +++ b/libnetwork/libnl3/lib/route/nexthop.c @@ -0,0 +1,290 @@ +/* + * lib/route/nexthop.c Routing Nexthop + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup route_obj + * @defgroup nexthop Nexthop + * @{ + */ + +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define NH_ATTR_FLAGS 0x000001 +#define NH_ATTR_WEIGHT 0x000002 +#define NH_ATTR_IFINDEX 0x000004 +#define NH_ATTR_GATEWAY 0x000008 +#define NH_ATTR_REALMS 0x000010 +/** @endcond */ + +/** + * @name Allocation/Freeing + * @{ + */ + +struct rtnl_nexthop *rtnl_route_nh_alloc(void) +{ + struct rtnl_nexthop *nh; + + nh = calloc(1, sizeof(*nh)); + if (!nh) + return NULL; + + nl_init_list_head(&nh->rtnh_list); + + return nh; +} + +struct rtnl_nexthop *rtnl_route_nh_clone(struct rtnl_nexthop *src) +{ + struct rtnl_nexthop *nh; + + nh = rtnl_route_nh_alloc(); + if (!nh) + return NULL; + + nh->rtnh_flags = src->rtnh_flags; + nh->rtnh_flag_mask = src->rtnh_flag_mask; + nh->rtnh_weight = src->rtnh_weight; + nh->rtnh_ifindex = src->rtnh_ifindex; + nh->ce_mask = src->ce_mask; + + if (src->rtnh_gateway) { + nh->rtnh_gateway = nl_addr_clone(src->rtnh_gateway); + if (!nh->rtnh_gateway) { + free(nh); + return NULL; + } + } + + return nh; +} + +void rtnl_route_nh_free(struct rtnl_nexthop *nh) +{ + nl_addr_put(nh->rtnh_gateway); + free(nh); +} + +/** @} */ + +int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b, + uint32_t attrs, int loose) +{ + int diff = 0; + +#define NH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NH_ATTR_##ATTR, a, b, EXPR) + + diff |= NH_DIFF(IFINDEX, a->rtnh_ifindex != b->rtnh_ifindex); + diff |= NH_DIFF(WEIGHT, a->rtnh_weight != b->rtnh_weight); + diff |= NH_DIFF(REALMS, a->rtnh_realms != b->rtnh_realms); + diff |= NH_DIFF(GATEWAY, nl_addr_cmp(a->rtnh_gateway, + b->rtnh_gateway)); + + if (loose) + diff |= NH_DIFF(FLAGS, + (a->rtnh_flags ^ b->rtnh_flags) & b->rtnh_flag_mask); + else + diff |= NH_DIFF(FLAGS, a->rtnh_flags != b->rtnh_flags); + +#undef NH_DIFF + + return diff; +} + +static void nh_dump_line(struct rtnl_nexthop *nh, struct nl_dump_params *dp) +{ + struct nl_cache *link_cache; + char buf[128]; + + link_cache = nl_cache_mngt_require("route/link"); + + nl_dump(dp, "via"); + + if (nh->ce_mask & NH_ATTR_GATEWAY) + nl_dump(dp, " %s", nl_addr2str(nh->rtnh_gateway, + buf, sizeof(buf))); + + if(nh->ce_mask & NH_ATTR_IFINDEX) { + if (link_cache) { + nl_dump(dp, " dev %s", + rtnl_link_i2name(link_cache, + nh->rtnh_ifindex, + buf, sizeof(buf))); + } else + nl_dump(dp, " dev %d", nh->rtnh_ifindex); + } + + nl_dump(dp, " "); +} + +static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp) +{ + struct nl_cache *link_cache; + char buf[128]; + + link_cache = nl_cache_mngt_require("route/link"); + + nl_dump(dp, "nexthop"); + + if (nh->ce_mask & NH_ATTR_GATEWAY) + nl_dump(dp, " via %s", nl_addr2str(nh->rtnh_gateway, + buf, sizeof(buf))); + + if(nh->ce_mask & NH_ATTR_IFINDEX) { + if (link_cache) { + nl_dump(dp, " dev %s", + rtnl_link_i2name(link_cache, + nh->rtnh_ifindex, + buf, sizeof(buf))); + } else + nl_dump(dp, " dev %d", nh->rtnh_ifindex); + } + + if (nh->ce_mask & NH_ATTR_WEIGHT) + nl_dump(dp, " weight %u", nh->rtnh_weight); + + if (nh->ce_mask & NH_ATTR_REALMS) + nl_dump(dp, " realm %04x:%04x", + RTNL_REALM_FROM(nh->rtnh_realms), + RTNL_REALM_TO(nh->rtnh_realms)); + + if (nh->ce_mask & NH_ATTR_FLAGS) + nl_dump(dp, " <%s>", rtnl_route_nh_flags2str(nh->rtnh_flags, + buf, sizeof(buf))); +} + +void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp) +{ + switch (dp->dp_type) { + case NL_DUMP_LINE: + nh_dump_line(nh, dp); + break; + + case NL_DUMP_DETAILS: + case NL_DUMP_STATS: + if (dp->dp_ivar == NH_DUMP_FROM_DETAILS) + nh_dump_details(nh, dp); + break; + + default: + break; + } +} + +/** + * @name Attributes + * @{ + */ + +void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, uint8_t weight) +{ + nh->rtnh_weight = weight; + nh->ce_mask |= NH_ATTR_WEIGHT; +} + +uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh) +{ + return nh->rtnh_weight; +} + +void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex) +{ + nh->rtnh_ifindex = ifindex; + nh->ce_mask |= NH_ATTR_IFINDEX; +} + +int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh) +{ + return nh->rtnh_ifindex; +} + +void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr) +{ + struct nl_addr *old = nh->rtnh_gateway; + + if (addr) { + nh->rtnh_gateway = nl_addr_get(addr); + nh->ce_mask |= NH_ATTR_GATEWAY; + } else { + nh->ce_mask &= ~NH_ATTR_GATEWAY; + nh->rtnh_gateway = NULL; + } + + if (old) + nl_addr_put(old); +} + +struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh) +{ + return nh->rtnh_gateway; +} + +void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags) +{ + nh->rtnh_flag_mask |= flags; + nh->rtnh_flags |= flags; + nh->ce_mask |= NH_ATTR_FLAGS; +} + +void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags) +{ + nh->rtnh_flag_mask |= flags; + nh->rtnh_flags &= ~flags; + nh->ce_mask |= NH_ATTR_FLAGS; +} + +unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh) +{ + return nh->rtnh_flags; +} + +void rtnl_route_nh_set_realms(struct rtnl_nexthop *nh, uint32_t realms) +{ + nh->rtnh_realms = realms; + nh->ce_mask |= NH_ATTR_REALMS; +} + +uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh) +{ + return nh->rtnh_realms; +} + +/** @} */ + +/** + * @name Nexthop Flags Translations + * @{ + */ + +static const struct trans_tbl nh_flags[] = { + __ADD(RTNH_F_DEAD, dead) + __ADD(RTNH_F_PERVASIVE, pervasive) + __ADD(RTNH_F_ONLINK, onlink) +}; + +char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len) +{ + return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags)); +} + +int rtnl_route_nh_str2flags(const char *name) +{ + return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags)); +} + +/** @} */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/pktloc.c b/libnetwork/libnl3/lib/route/pktloc.c new file mode 100644 index 0000000..e7dffe5 --- /dev/null +++ b/libnetwork/libnl3/lib/route/pktloc.c @@ -0,0 +1,260 @@ +/* + * lib/route/pktloc.c Packet Location Aliasing + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2011 Thomas Graf + */ + +/** + * @ingroup tc + * @defgroup pktloc Packet Location Aliasing + * Packet Location Aliasing + * + * The packet location aliasing interface eases the use of offset definitions + * inside packets by allowing them to be referenced by name. Known positions + * of protocol fields are stored in a configuration file and associated with + * a name for later reference. The configuration file is distributed with the + * library and provides a well defined set of definitions for most common + * protocol fields. + * + * @section pktloc_examples Examples + * @par Example 1.1 Looking up a packet location + * @code + * struct rtnl_pktloc *loc; + * + * rtnl_pktloc_lookup("ip.src", &loc); + * @endcode + * @{ + */ + +#include +#include +#include +#include +#include + +#include "pktloc_syntax.h" +#include "pktloc_grammar.h" + +/** @cond SKIP */ +#define PKTLOC_NAME_HT_SIZ 256 + +static struct nl_list_head pktloc_name_ht[PKTLOC_NAME_HT_SIZ]; + +/* djb2 */ +static unsigned int pktloc_hash(const char *str) +{ + unsigned long hash = 5381; + int c; + + while ((c = *str++)) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + + return hash % PKTLOC_NAME_HT_SIZ; +} + +static int __pktloc_lookup(const char *name, struct rtnl_pktloc **result) +{ + struct rtnl_pktloc *loc; + int hash; + + hash = pktloc_hash(name); + nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) { + if (!strcasecmp(loc->name, name)) { + loc->refcnt++; + *result = loc; + return 0; + } + } + + return -NLE_OBJ_NOTFOUND; +} + +extern int pktloc_parse(void *scanner); + +static void rtnl_pktloc_free(struct rtnl_pktloc *loc) +{ + if (!loc) + return; + + free(loc->name); + free(loc); +} + +static int read_pktlocs(void) +{ + YY_BUFFER_STATE buf = NULL; + yyscan_t scanner = NULL; + static time_t last_read; + struct stat st = {0}; + char *path; + int i, err; + FILE *fd; + + if (build_sysconf_path(&path, "pktloc") < 0) + return -NLE_NOMEM; + + /* if stat fails, just try to read the file */ + if (stat(path, &st) == 0) { + /* Don't re-read file if file is unchanged */ + if (last_read == st.st_mtime) + return 0; + } + + NL_DBG(2, "Reading packet location file \"%s\"\n", path); + + if (!(fd = fopen(path, "r"))) { + err = -NLE_PKTLOC_FILE; + goto errout; + } + + for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) { + struct rtnl_pktloc *loc, *n; + + nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list) + rtnl_pktloc_put(loc); + + nl_init_list_head(&pktloc_name_ht[i]); + } + + if ((err = pktloc_lex_init(&scanner)) < 0) { + err = -NLE_FAILURE; + goto errout_close; + } + + buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner); + pktloc__switch_to_buffer(buf, scanner); + + if ((err = pktloc_parse(scanner)) != 0) { + pktloc__delete_buffer(buf, scanner); + err = -NLE_PARSE_ERR; + goto errout_scanner; + } + + last_read = st.st_mtime; + +errout_scanner: + if (scanner) + pktloc_lex_destroy(scanner); +errout_close: + fclose(fd); +errout: + free(path); + + return 0; +} + +/** @endcond */ + +/** + * Lookup packet location alias + * @arg name Name of packet location. + * @arg result Result pointer + * + * Tries to find a matching packet location alias for the supplied + * packet location name. + * + * The file containing the packet location definitions is automatically + * re-read if its modification time has changed since the last call. + * + * The returned packet location has to be returned after use by calling + * rtnl_pktloc_put() in order to allow freeing its memory after the last + * user has abandoned it. + * + * @return 0 on success or a negative error code. + * @retval NLE_PKTLOC_FILE Unable to open packet location file. + * @retval NLE_OBJ_NOTFOUND No matching packet location alias found. + */ +int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result) +{ + int err; + + if ((err = read_pktlocs()) < 0) + return err; + + return __pktloc_lookup(name, result); +} + +/** + * Allocate packet location object + */ +struct rtnl_pktloc *rtnl_pktloc_alloc(void) +{ + struct rtnl_pktloc *loc; + + if (!(loc = calloc(1, sizeof(*loc)))) + return NULL; + + loc->refcnt = 1; + nl_init_list_head(&loc->list); + + return loc; +} + +/** + * Return reference of a packet location + * @arg loc packet location object. + */ +void rtnl_pktloc_put(struct rtnl_pktloc *loc) +{ + if (!loc) + return; + + loc->refcnt--; + if (loc->refcnt <= 0) + rtnl_pktloc_free(loc); +} + +/** + * Add a packet location to the hash table + * @arg loc packet location object + * + * @return 0 on success or a negative error code. + */ +int rtnl_pktloc_add(struct rtnl_pktloc *loc) +{ + struct rtnl_pktloc *l; + + if (__pktloc_lookup(loc->name, &l) == 0) { + rtnl_pktloc_put(l); + return -NLE_EXIST; + } + + NL_DBG(2, "New packet location entry \"%s\" align=%u layer=%u " + "offset=%u mask=%#x shift=%u refnt=%u\n", + loc->name, loc->align, loc->layer, loc->offset, + loc->mask, loc->shift, loc->refcnt); + + nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]); + + return 0; +} + +void rtnl_pktloc_foreach(void (*cb)(struct rtnl_pktloc *, void *), void *arg) +{ + struct rtnl_pktloc *loc; + int i; + + /* ignore errors */ + read_pktlocs(); + + for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) + nl_list_for_each_entry(loc, &pktloc_name_ht[i], list) + cb(loc, arg); +} + +static int __init pktloc_init(void) +{ + int i; + + for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) + nl_init_list_head(&pktloc_name_ht[i]); + + return 0; +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/pktloc_grammar.l b/libnetwork/libnl3/lib/route/pktloc_grammar.l new file mode 100644 index 0000000..6b7a933 --- /dev/null +++ b/libnetwork/libnl3/lib/route/pktloc_grammar.l @@ -0,0 +1,51 @@ +%{ + #include + #include + #include + #include + #include + #include "pktloc_syntax.h" +%} + +%option 8bit +%option reentrant +%option warn +%option noyywrap +%option noinput +%option nounput +%option bison-bridge +%option bison-locations +%option prefix="pktloc_" + +%% + +[ \t\r\n]+ + +"#".* + +[[:digit:]]+ | +0[xX][[:xdigit:]]+ { + yylval->i = strtoul(yytext, NULL, 0); + return NUMBER; + } + +"+" { return yylval->i = yytext[0]; } + +[uU]8 { yylval->i = TCF_EM_ALIGN_U8; return ALIGN; } +[uU]16 { yylval->i = TCF_EM_ALIGN_U16; return ALIGN; } +[uU]32 { yylval->i = TCF_EM_ALIGN_U32; return ALIGN; } + +[lL][iI][nN][kK] | +[eE][tT][hH] { yylval->i = TCF_LAYER_LINK; return LAYER; } +[nN][eE][tT] | +[iI][pP] { yylval->i = TCF_LAYER_NETWORK; return LAYER; } +[tT][rR][aA][nN][sS][pP][oO][rR][tT] | +[tT][cC][pP] { yylval->i = TCF_LAYER_TRANSPORT; return LAYER; } + + +[^ \t\r\n+]+ { + yylval->s = strdup(yytext); + if (yylval->s == NULL) + return ERROR; + return NAME; + } diff --git a/libnetwork/libnl3/lib/route/pktloc_syntax.y b/libnetwork/libnl3/lib/route/pktloc_syntax.y new file mode 100644 index 0000000..4a2ce48 --- /dev/null +++ b/libnetwork/libnl3/lib/route/pktloc_syntax.y @@ -0,0 +1,103 @@ +%{ +#include +#include +#include +#include +#include +%} + +%locations +%error-verbose +%define api.pure +%name-prefix "pktloc_" + +%parse-param {void *scanner} +%lex-param {void *scanner} +%expect 1 + +%union { + struct rtnl_pktloc *l; + uint32_t i; + char *s; +} + +%{ +extern int pktloc_lex(YYSTYPE *, YYLTYPE *, void *); + +static void yyerror(YYLTYPE *locp, void *scanner, const char *msg) +{ + NL_DBG(1, "Error while parsing packet location file: %s\n", msg); +} +%} + +%token ERROR NUMBER LAYER ALIGN +%token NAME + +%type mask layer align shift +%type location + +%destructor { free($$); } NAME + +%start input + +%% + +input: + /* empty */ + | location input + ; + +location: + NAME align layer NUMBER mask shift + { + struct rtnl_pktloc *loc; + + if (!(loc = rtnl_pktloc_alloc())) { + NL_DBG(1, "Allocating a packet location " + "object failed.\n"); + YYABORT; + } + + loc->name = $1; + loc->align = $2; + loc->layer = $3; + loc->offset = $4; + loc->mask = $5; + loc->shift = $6; + + if (rtnl_pktloc_add(loc) < 0) { + NL_DBG(1, "Duplicate packet location entry " + "\"%s\"\n", $1); + } + + $$ = loc; + } + ; + +align: + ALIGN + { $$ = $1; } + | NUMBER + { $$ = $1; } + ; + +layer: + /* empty */ + { $$ = TCF_LAYER_NETWORK; } + | LAYER '+' + { $$ = $1; } + ; + +mask: + /* empty */ + { $$ = 0; } + | NUMBER + { $$ = $1; } + ; + +shift: + /* empty */ + { $$ = 0; } + | NUMBER + { $$ = $1; } + ; diff --git a/libnetwork/libnl3/lib/route/qdisc.c b/libnetwork/libnl3/lib/route/qdisc.c new file mode 100644 index 0000000..e5a8aa0 --- /dev/null +++ b/libnetwork/libnl3/lib/route/qdisc.c @@ -0,0 +1,575 @@ +/* + * lib/route/qdisc.c Queueing Disciplines + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +/** + * @ingroup tc + * @defgroup qdisc Queueing Disciplines + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct nl_cache_ops rtnl_qdisc_ops; +static struct nl_object_ops qdisc_obj_ops; + +static int qdisc_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *n, struct nl_parser_param *pp) +{ + struct rtnl_qdisc *qdisc; + int err; + + if (!(qdisc = rtnl_qdisc_alloc())) + return -NLE_NOMEM; + + if ((err = rtnl_tc_msg_parse(n, TC_CAST(qdisc))) < 0) + goto errout; + + err = pp->pp_cb(OBJ_CAST(qdisc), pp); +errout: + rtnl_qdisc_put(qdisc); + + return err; +} + +static int qdisc_request_update(struct nl_cache *c, struct nl_sock *sk) +{ + struct tcmsg tchdr = { + .tcm_family = AF_UNSPEC, + .tcm_ifindex = c->c_iarg1, + }; + + return nl_send_simple(sk, RTM_GETQDISC, NLM_F_DUMP, &tchdr, + sizeof(tchdr)); +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct rtnl_qdisc *rtnl_qdisc_alloc(void) +{ + struct rtnl_tc *tc; + + tc = TC_CAST(nl_object_alloc(&qdisc_obj_ops)); + if (tc) + tc->tc_type = RTNL_TC_TYPE_QDISC; + + return (struct rtnl_qdisc *) tc; +} + +void rtnl_qdisc_put(struct rtnl_qdisc *qdisc) +{ + nl_object_put((struct nl_object *) qdisc); +} + +/** @} */ + +/** + * @name Addition / Modification / Deletion + * @{ + */ + +static int build_qdisc_msg(struct rtnl_qdisc *qdisc, int type, int flags, + struct nl_msg **result) +{ + if (!(qdisc->ce_mask & TCA_ATTR_IFINDEX)) { + APPBUG("ifindex must be specified"); + return -NLE_MISSING_ATTR; + } + + return rtnl_tc_msg_build(TC_CAST(qdisc), type, flags, result); +} + +/** + * Build a netlink message requesting the addition of a qdisc + * @arg qdisc Qdisc to add + * @arg flags Additional netlink message flags + * @arg result Pointer to store resulting netlink message + * + * The behaviour of this function is identical to rtnl_qdisc_add() with + * the exception that it will not send the message but return it int the + * provided return pointer instead. + * + * @see rtnl_qdisc_add() + * + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc, int flags, + struct nl_msg **result) +{ + if (!(qdisc->ce_mask & (TCA_ATTR_HANDLE | TCA_ATTR_PARENT))) { + APPBUG("handle or parent must be specified"); + return -NLE_MISSING_ATTR; + } + + return build_qdisc_msg(qdisc, RTM_NEWQDISC, flags, result); +} + +/** + * Add qdisc + * @arg sk Netlink socket + * @arg qdisc Qdisc to add + * @arg flags Additional netlink message flags + * + * Builds a \c RTM_NEWQDISC netlink message requesting the addition + * of a new qdisc and sends the message to the kernel. The configuration + * of the qdisc is derived from the attributes of the specified qdisc. + * + * The following flags may be specified: + * - \c NLM_F_CREATE: Create qdisc if it does not exist, otherwise + * -NLE_OBJ_NOTFOUND is returned. + * - \c NLM_F_REPLACE: If another qdisc is already attached to the + * parent, replace it even if the handles mismatch. + * - \c NLM_F_EXCL: Return -NLE_EXISTS if a qdisc with matching + * handle exists already. + * + * Existing qdiscs with matching handles will be updated, unless the + * flag \c NLM_F_EXCL is specified. If their handles do not match, the + * error -NLE_EXISTS is returned unless the flag \c NLM_F_REPLACE is + * specified in which case the existing qdisc is replaced with the new + * one. If no matching qdisc exists, it will be created if the flag + * \c NLM_F_CREATE is set, otherwise the error -NLE_OBJ_NOTFOUND is + * returned. + * + * After sending, the function will wait for the ACK or an eventual + * error message to be received and will therefore block until the + * operation has been completed. + * + * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause + * this function to return immediately after sending. In this case, + * it is the responsibility of the caller to handle any error + * messages returned. + * + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_add(struct nl_sock *sk, struct rtnl_qdisc *qdisc, int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_qdisc_build_add_request(qdisc, flags, &msg)) < 0) + return err; + + return nl_send_sync(sk, msg); +} + +/** + * Build netlink message requesting the update of a qdisc + * @arg qdisc Qdisc to update + * @arg new Qdisc with updated attributes + * @arg flags Additional netlink message flags + * @arg result Pointer to store resulting netlink message + * + * The behaviour of this function is identical to rtnl_qdisc_update() with + * the exception that it will not send the message but return it in the + * provided return pointer instead. + * + * @see rtnl_qdisc_update() + * + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_build_update_request(struct rtnl_qdisc *qdisc, + struct rtnl_qdisc *new, int flags, + struct nl_msg **result) +{ + if (flags & (NLM_F_CREATE | NLM_F_EXCL)) { + APPBUG("NLM_F_CREATE and NLM_F_EXCL may not be used here, " + "use rtnl_qdisc_add()"); + return -NLE_INVAL; + } + + if (!(qdisc->ce_mask & TCA_ATTR_IFINDEX)) { + APPBUG("ifindex must be specified"); + return -NLE_MISSING_ATTR; + } + + if (!(qdisc->ce_mask & (TCA_ATTR_HANDLE | TCA_ATTR_PARENT))) { + APPBUG("handle or parent must be specified"); + return -NLE_MISSING_ATTR; + } + + rtnl_tc_set_ifindex(TC_CAST(new), qdisc->q_ifindex); + + if (qdisc->ce_mask & TCA_ATTR_HANDLE) + rtnl_tc_set_handle(TC_CAST(new), qdisc->q_handle); + + if (qdisc->ce_mask & TCA_ATTR_PARENT) + rtnl_tc_set_parent(TC_CAST(new), qdisc->q_parent); + + return build_qdisc_msg(new, RTM_NEWQDISC, flags, result); +} + +/** + * Update qdisc + * @arg sk Netlink socket + * @arg qdisc Qdisc to update + * @arg new Qdisc with updated attributes + * @arg flags Additional netlink message flags + * + * Builds a \c RTM_NEWQDISC netlink message requesting the update + * of an existing qdisc and sends the message to the kernel. + * + * This function is a varation of rtnl_qdisc_add() to update qdiscs + * if the qdisc to be updated is available as qdisc object. The + * behaviour is identical to the one of rtnl_qdisc_add except that + * before constructing the message, it copies the \c ifindex, + * \c handle, and \c parent from the original \p qdisc to the \p new + * qdisc. + * + * After sending, the function will wait for the ACK or an eventual + * error message to be received and will therefore block until the + * operation has been completed. + * + * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause + * this function to return immediately after sending. In this case, + * it is the responsibility of the caller to handle any error + * messages returned. + * + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_update(struct nl_sock *sk, struct rtnl_qdisc *qdisc, + struct rtnl_qdisc *new, int flags) +{ + struct nl_msg *msg; + int err; + + err = rtnl_qdisc_build_update_request(qdisc, new, flags, &msg); + if (err < 0) + return err; + + return nl_send_sync(sk, msg); +} + +/** + * Build netlink message requesting the deletion of a qdisc + * @arg qdisc Qdisc to delete + * @arg result Pointer to store resulting netlink message + * + * The behaviour of this function is identical to rtnl_qdisc_delete() with + * the exception that it will not send the message but return it in the + * provided return pointer instead. + * + * @see rtnl_qdisc_delete() + * + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc, + struct nl_msg **result) +{ + struct nl_msg *msg; + struct tcmsg tchdr; + int required = TCA_ATTR_IFINDEX | TCA_ATTR_PARENT; + + if ((qdisc->ce_mask & required) != required) { + APPBUG("ifindex and parent must be specified"); + return -NLE_MISSING_ATTR; + } + + if (!(msg = nlmsg_alloc_simple(RTM_DELQDISC, 0))) + return -NLE_NOMEM; + + memset(&tchdr, 0, sizeof(tchdr)); + + tchdr.tcm_family = AF_UNSPEC; + tchdr.tcm_ifindex = qdisc->q_ifindex; + tchdr.tcm_parent = qdisc->q_parent; + + if (qdisc->ce_mask & TCA_ATTR_HANDLE) + tchdr.tcm_handle = qdisc->q_handle; + + if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + if (qdisc->ce_mask & TCA_ATTR_KIND) + NLA_PUT_STRING(msg, TCA_KIND, qdisc->q_kind); + + *result = msg; + return 0; + +nla_put_failure: + nlmsg_free(msg); + return -NLE_MSGSIZE; +} + +/** + * Delete qdisc + * @arg sk Netlink socket + * @arg qdisc Qdisc to add + * + * Builds a \c RTM_NEWQDISC netlink message requesting the deletion + * of a qdisc and sends the message to the kernel. + * + * The message is constructed out of the following attributes: + * - \c ifindex and \c parent + * - \c handle (optional, must match if provided) + * - \c kind (optional, must match if provided) + * + * All other qdisc attributes including all qdisc type specific + * attributes are ignored. + * + * After sending, the function will wait for the ACK or an eventual + * error message to be received and will therefore block until the + * operation has been completed. + * + * @note It is not possible to delete default qdiscs. + * + * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause + * this function to return immediately after sending. In this case, + * it is the responsibility of the caller to handle any error + * messages returned. + * + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_delete(struct nl_sock *sk, struct rtnl_qdisc *qdisc) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_qdisc_build_delete_request(qdisc, &msg)) < 0) + return err; + + return nl_send_sync(sk, msg); +} + +/** @} */ + +/** + * @name Cache Related Functions + * @{ + */ + +/** + * Allocate a cache and fill it with all configured qdiscs + * @arg sk Netlink socket + * @arg result Pointer to store the created cache + * + * Allocates a new qdisc cache and fills it with a list of all configured + * qdiscs on all network devices. Release the cache with nl_cache_free(). + * + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_alloc_cache(struct nl_sock *sk, struct nl_cache **result) +{ + return nl_cache_alloc_and_fill(&rtnl_qdisc_ops, sk, result); +} + +/** + * Search qdisc by interface index and parent + * @arg cache Qdisc cache + * @arg ifindex Interface index + * @arg parent Handle of parent qdisc + * + * Searches a qdisc cache previously allocated with rtnl_qdisc_alloc_cache() + * and searches for a qdisc matching the interface index and parent qdisc. + * + * The reference counter is incremented before returning the qdisc, therefore + * the reference must be given back with rtnl_qdisc_put() after usage. + * + * @return pointer to qdisc inside the cache or NULL if no match was found. + */ +struct rtnl_qdisc *rtnl_qdisc_get_by_parent(struct nl_cache *cache, + int ifindex, uint32_t parent) +{ + struct rtnl_qdisc *q; + + if (cache->c_ops != &rtnl_qdisc_ops) + return NULL; + + nl_list_for_each_entry(q, &cache->c_items, ce_list) { + if (q->q_parent == parent && q->q_ifindex == ifindex) { + nl_object_get((struct nl_object *) q); + return q; + } + } + + return NULL; +} + +/** + * Search qdisc by interface index and handle + * @arg cache Qdisc cache + * @arg ifindex Interface index + * @arg handle Handle + * + * Searches a qdisc cache previously allocated with rtnl_qdisc_alloc_cache() + * and searches for a qdisc matching the interface index and handle. + * + * The reference counter is incremented before returning the qdisc, therefore + * the reference must be given back with rtnl_qdisc_put() after usage. + * + * @return Qdisc or NULL if no match was found. + */ +struct rtnl_qdisc *rtnl_qdisc_get(struct nl_cache *cache, int ifindex, + uint32_t handle) +{ + struct rtnl_qdisc *q; + + if (cache->c_ops != &rtnl_qdisc_ops) + return NULL; + + nl_list_for_each_entry(q, &cache->c_items, ce_list) { + if (q->q_handle == handle && q->q_ifindex == ifindex) { + nl_object_get((struct nl_object *) q); + return q; + } + } + + return NULL; +} + +/** @} */ + +/** + * @name Deprecated Functions + * @{ + */ + +/** + * Call a callback for each child class of a qdisc (deprecated) + * + * @deprecated Use of this function is deprecated, it does not allow + * to handle the out of memory situation that can occur. + */ +void rtnl_qdisc_foreach_child(struct rtnl_qdisc *qdisc, struct nl_cache *cache, + void (*cb)(struct nl_object *, void *), void *arg) +{ + struct rtnl_class *filter; + + filter = rtnl_class_alloc(); + if (!filter) + return; + + rtnl_tc_set_parent(TC_CAST(filter), qdisc->q_handle); + rtnl_tc_set_ifindex(TC_CAST(filter), qdisc->q_ifindex); + rtnl_tc_set_kind(TC_CAST(filter), qdisc->q_kind); + + nl_cache_foreach_filter(cache, OBJ_CAST(filter), cb, arg); + + rtnl_class_put(filter); +} + +/** + * Call a callback for each filter attached to the qdisc (deprecated) + * + * @deprecated Use of this function is deprecated, it does not allow + * to handle the out of memory situation that can occur. + */ +void rtnl_qdisc_foreach_cls(struct rtnl_qdisc *qdisc, struct nl_cache *cache, + void (*cb)(struct nl_object *, void *), void *arg) +{ + struct rtnl_cls *filter; + + if (!(filter = rtnl_cls_alloc())) + return; + + rtnl_tc_set_ifindex(TC_CAST(filter), qdisc->q_ifindex); + rtnl_tc_set_parent(TC_CAST(filter), qdisc->q_parent); + + nl_cache_foreach_filter(cache, OBJ_CAST(filter), cb, arg); + rtnl_cls_put(filter); +} + +/** + * Build a netlink message requesting the update of a qdisc + * + * @deprecated Use of this function is deprecated in favour of + * rtnl_qdisc_build_update_request() due to the missing + * possibility of specifying additional flags. + */ +int rtnl_qdisc_build_change_request(struct rtnl_qdisc *qdisc, + struct rtnl_qdisc *new, + struct nl_msg **result) +{ + return rtnl_qdisc_build_update_request(qdisc, new, NLM_F_REPLACE, + result); +} + +/** + * Change attributes of a qdisc + * + * @deprecated Use of this function is deprecated in favour of + * rtnl_qdisc_update() due to the missing possibility of + * specifying additional flags. + */ +int rtnl_qdisc_change(struct nl_sock *sk, struct rtnl_qdisc *qdisc, + struct rtnl_qdisc *new) +{ + return rtnl_qdisc_update(sk, qdisc, new, NLM_F_REPLACE); +} + +/** @} */ + +static void qdisc_dump_details(struct rtnl_tc *tc, struct nl_dump_params *p) +{ + struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc; + + nl_dump(p, "refcnt %u ", qdisc->q_info); +} + +static struct rtnl_tc_type_ops qdisc_ops = { + .tt_type = RTNL_TC_TYPE_QDISC, + .tt_dump_prefix = "qdisc", + .tt_dump = { + [NL_DUMP_DETAILS] = qdisc_dump_details, + }, +}; + +static struct nl_cache_ops rtnl_qdisc_ops = { + .co_name = "route/qdisc", + .co_hdrsize = sizeof(struct tcmsg), + .co_msgtypes = { + { RTM_NEWQDISC, NL_ACT_NEW, "new" }, + { RTM_DELQDISC, NL_ACT_DEL, "del" }, + { RTM_GETQDISC, NL_ACT_GET, "get" }, + END_OF_MSGTYPES_LIST, + }, + .co_protocol = NETLINK_ROUTE, + .co_request_update = qdisc_request_update, + .co_msg_parser = qdisc_msg_parser, + .co_obj_ops = &qdisc_obj_ops, +}; + +static struct nl_object_ops qdisc_obj_ops = { + .oo_name = "route/qdisc", + .oo_size = sizeof(struct rtnl_qdisc), + .oo_free_data = rtnl_tc_free_data, + .oo_clone = rtnl_tc_clone, + .oo_dump = { + [NL_DUMP_LINE] = rtnl_tc_dump_line, + [NL_DUMP_DETAILS] = rtnl_tc_dump_details, + [NL_DUMP_STATS] = rtnl_tc_dump_stats, + }, + .oo_compare = rtnl_tc_compare, + .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE), +}; + +static void __init qdisc_init(void) +{ + rtnl_tc_type_register(&qdisc_ops); + nl_cache_mngt_register(&rtnl_qdisc_ops); +} + +static void __exit qdisc_exit(void) +{ + nl_cache_mngt_unregister(&rtnl_qdisc_ops); + rtnl_tc_type_unregister(&qdisc_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/qdisc/.dirstamp b/libnetwork/libnl3/lib/route/qdisc/.dirstamp new file mode 100644 index 0000000..e69de29 diff --git a/libnetwork/libnl3/lib/route/qdisc/blackhole.c b/libnetwork/libnl3/lib/route/qdisc/blackhole.c new file mode 100644 index 0000000..06f5380 --- /dev/null +++ b/libnetwork/libnl3/lib/route/qdisc/blackhole.c @@ -0,0 +1,37 @@ +/* + * lib/route/qdisc/blackhole.c Blackhole Qdisc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +/** + * @ingroup qdisc + * @defgroup qdisc_blackhole Blackhole + * @{ + */ + +#include +#include +#include + +static struct rtnl_tc_ops blackhole_ops = { + .to_kind = "blackhole", + .to_type = RTNL_TC_TYPE_QDISC, +}; + +static void __init blackhole_init(void) +{ + rtnl_tc_register(&blackhole_ops); +} + +static void __exit blackhole_exit(void) +{ + rtnl_tc_unregister(&blackhole_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/qdisc/cbq.c b/libnetwork/libnl3/lib/route/qdisc/cbq.c new file mode 100644 index 0000000..e791a10 --- /dev/null +++ b/libnetwork/libnl3/lib/route/qdisc/cbq.c @@ -0,0 +1,204 @@ +/* + * lib/route/qdisc/cbq.c Class Based Queueing + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @ingroup qdisc + * @ingroup class + * @defgroup qdisc_cbq Class Based Queueing (CBQ) + * @{ + */ + +static const struct trans_tbl ovl_strategies[] = { + __ADD(TC_CBQ_OVL_CLASSIC,classic) + __ADD(TC_CBQ_OVL_DELAY,delay) + __ADD(TC_CBQ_OVL_LOWPRIO,lowprio) + __ADD(TC_CBQ_OVL_DROP,drop) + __ADD(TC_CBQ_OVL_RCLASSIC,rclassic) +}; + +/** + * Convert a CBQ OVL strategy to a character string + * @arg type CBQ OVL strategy + * @arg buf destination buffer + * @arg len length of destination buffer + * + * Converts a CBQ OVL strategy to a character string and stores in the + * provided buffer. Returns the destination buffer or the type + * encoded in hex if no match was found. + */ +char *nl_ovl_strategy2str(int type, char *buf, size_t len) +{ + return __type2str(type, buf, len, ovl_strategies, + ARRAY_SIZE(ovl_strategies)); +} + +/** + * Convert a string to a CBQ OVL strategy + * @arg name CBQ OVL stragegy name + * + * Converts a CBQ OVL stragegy name to it's corresponding CBQ OVL strategy + * type. Returns the type or -1 if none was found. + */ +int nl_str2ovl_strategy(const char *name) +{ + return __str2type(name, ovl_strategies, ARRAY_SIZE(ovl_strategies)); +} + +static struct nla_policy cbq_policy[TCA_CBQ_MAX+1] = { + [TCA_CBQ_LSSOPT] = { .minlen = sizeof(struct tc_cbq_lssopt) }, + [TCA_CBQ_RATE] = { .minlen = sizeof(struct tc_ratespec) }, + [TCA_CBQ_WRROPT] = { .minlen = sizeof(struct tc_cbq_wrropt) }, + [TCA_CBQ_OVL_STRATEGY] = { .minlen = sizeof(struct tc_cbq_ovl) }, + [TCA_CBQ_FOPT] = { .minlen = sizeof(struct tc_cbq_fopt) }, + [TCA_CBQ_POLICE] = { .minlen = sizeof(struct tc_cbq_police) }, +}; + +static int cbq_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct nlattr *tb[TCA_CBQ_MAX + 1]; + struct rtnl_cbq *cbq = data; + int err; + + err = tca_parse(tb, TCA_CBQ_MAX, tc, cbq_policy); + if (err < 0) + return err; + + nla_memcpy(&cbq->cbq_lss, tb[TCA_CBQ_LSSOPT], sizeof(cbq->cbq_lss)); + nla_memcpy(&cbq->cbq_rate, tb[TCA_CBQ_RATE], sizeof(cbq->cbq_rate)); + nla_memcpy(&cbq->cbq_wrr, tb[TCA_CBQ_WRROPT], sizeof(cbq->cbq_wrr)); + nla_memcpy(&cbq->cbq_fopt, tb[TCA_CBQ_FOPT], sizeof(cbq->cbq_fopt)); + nla_memcpy(&cbq->cbq_ovl, tb[TCA_CBQ_OVL_STRATEGY], + sizeof(cbq->cbq_ovl)); + nla_memcpy(&cbq->cbq_police, tb[TCA_CBQ_POLICE], + sizeof(cbq->cbq_police)); + + return 0; +} + +static void cbq_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_cbq *cbq = data; + double r, rbit; + char *ru, *rubit; + + if (!cbq) + return; + + r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru); + rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit); + + nl_dump(p, " rate %.2f%s/s (%.0f%s) prio %u", + r, ru, rbit, rubit, cbq->cbq_wrr.priority); +} + +static void cbq_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_cbq *cbq = data; + char *unit, buf[32]; + double w; + uint32_t el; + + if (!cbq) + return; + + w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit); + + nl_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n", + cbq->cbq_lss.avpkt, + cbq->cbq_rate.mpu, + 1 << cbq->cbq_rate.cell_log, + cbq->cbq_wrr.allot, w, unit); + + el = cbq->cbq_lss.ewma_log; + nl_dump_line(p, " minidle %uus maxidle %uus offtime " + "%uus level %u ewma_log %u\n", + nl_ticks2us(cbq->cbq_lss.minidle >> el), + nl_ticks2us(cbq->cbq_lss.maxidle >> el), + nl_ticks2us(cbq->cbq_lss.offtime >> el), + cbq->cbq_lss.level, + cbq->cbq_lss.ewma_log); + + nl_dump_line(p, " penalty %uus strategy %s ", + nl_ticks2us(cbq->cbq_ovl.penalty), + nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf))); + + nl_dump(p, "split %s defmap 0x%08x ", + rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)), + cbq->cbq_fopt.defmap); + + nl_dump(p, "police %s", + nl_police2str(cbq->cbq_police.police, buf, sizeof(buf))); +} + +static void cbq_dump_stats(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct tc_cbq_xstats *x; + + if (!(x = tca_xstats(tc))) + return; + + nl_dump_line(p, " borrows overact " + " avgidle undertime\n"); + nl_dump_line(p, " %10u %10u %10u %10u\n", + x->borrows, x->overactions, x->avgidle, x->undertime); +} + +static struct rtnl_tc_ops cbq_qdisc_ops = { + .to_kind = "cbq", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_cbq), + .to_msg_parser = cbq_msg_parser, + .to_dump = { + [NL_DUMP_LINE] = cbq_dump_line, + [NL_DUMP_DETAILS] = cbq_dump_details, + [NL_DUMP_STATS] = cbq_dump_stats, + }, +}; + +static struct rtnl_tc_ops cbq_class_ops = { + .to_kind = "cbq", + .to_type = RTNL_TC_TYPE_CLASS, + .to_size = sizeof(struct rtnl_cbq), + .to_msg_parser = cbq_msg_parser, + .to_dump = { + [NL_DUMP_LINE] = cbq_dump_line, + [NL_DUMP_DETAILS] = cbq_dump_details, + [NL_DUMP_STATS] = cbq_dump_stats, + }, +}; + +static void __init cbq_init(void) +{ + rtnl_tc_register(&cbq_qdisc_ops); + rtnl_tc_register(&cbq_class_ops); +} + +static void __exit cbq_exit(void) +{ + rtnl_tc_unregister(&cbq_qdisc_ops); + rtnl_tc_unregister(&cbq_class_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/qdisc/dsmark.c b/libnetwork/libnl3/lib/route/qdisc/dsmark.c new file mode 100644 index 0000000..b5fd0d6 --- /dev/null +++ b/libnetwork/libnl3/lib/route/qdisc/dsmark.c @@ -0,0 +1,413 @@ +/* + * lib/route/qdisc/dsmark.c DSMARK + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +/** + * @ingroup qdisc + * @ingroup class + * @defgroup qdisc_dsmark Differentiated Services Marker (DSMARK) + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define SCH_DSMARK_ATTR_INDICES 0x1 +#define SCH_DSMARK_ATTR_DEFAULT_INDEX 0x2 +#define SCH_DSMARK_ATTR_SET_TC_INDEX 0x4 + +#define SCH_DSMARK_ATTR_MASK 0x1 +#define SCH_DSMARK_ATTR_VALUE 0x2 +/** @endcond */ + +static struct nla_policy dsmark_policy[TCA_DSMARK_MAX+1] = { + [TCA_DSMARK_INDICES] = { .type = NLA_U16 }, + [TCA_DSMARK_DEFAULT_INDEX] = { .type = NLA_U16 }, + [TCA_DSMARK_SET_TC_INDEX] = { .type = NLA_FLAG }, + [TCA_DSMARK_VALUE] = { .type = NLA_U8 }, + [TCA_DSMARK_MASK] = { .type = NLA_U8 }, +}; + +static int dsmark_qdisc_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct rtnl_dsmark_qdisc *dsmark = data; + struct nlattr *tb[TCA_DSMARK_MAX + 1]; + int err; + + err = tca_parse(tb, TCA_DSMARK_MAX, tc, dsmark_policy); + if (err < 0) + return err; + + if (tb[TCA_DSMARK_INDICES]) { + dsmark->qdm_indices = nla_get_u16(tb[TCA_DSMARK_INDICES]); + dsmark->qdm_mask |= SCH_DSMARK_ATTR_INDICES; + } + + if (tb[TCA_DSMARK_DEFAULT_INDEX]) { + dsmark->qdm_default_index = + nla_get_u16(tb[TCA_DSMARK_DEFAULT_INDEX]); + dsmark->qdm_mask |= SCH_DSMARK_ATTR_DEFAULT_INDEX; + } + + if (tb[TCA_DSMARK_SET_TC_INDEX]) { + dsmark->qdm_set_tc_index = 1; + dsmark->qdm_mask |= SCH_DSMARK_ATTR_SET_TC_INDEX; + } + + return 0; +} + +static int dsmark_class_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct rtnl_dsmark_class *dsmark = data; + struct nlattr *tb[TCA_DSMARK_MAX + 1]; + int err; + + err = tca_parse(tb, TCA_DSMARK_MAX, tc, dsmark_policy); + if (err < 0) + return err; + + if (tb[TCA_DSMARK_MASK]) { + dsmark->cdm_bmask = nla_get_u8(tb[TCA_DSMARK_MASK]); + dsmark->cdm_mask |= SCH_DSMARK_ATTR_MASK; + } + + if (tb[TCA_DSMARK_VALUE]) { + dsmark->cdm_value = nla_get_u8(tb[TCA_DSMARK_VALUE]); + dsmark->cdm_mask |= SCH_DSMARK_ATTR_VALUE; + } + + return 0; +} + +static void dsmark_qdisc_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_dsmark_qdisc *dsmark = data; + + if (dsmark && (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES)) + nl_dump(p, " indices 0x%04x", dsmark->qdm_indices); +} + +static void dsmark_qdisc_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_dsmark_qdisc *dsmark = data; + + if (!dsmark) + return; + + if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX) + nl_dump(p, " default index 0x%04x", dsmark->qdm_default_index); + + if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX) + nl_dump(p, " set-tc-index"); +} + +static void dsmark_class_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_dsmark_class *dsmark = data; + + if (!dsmark) + return; + + if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE) + nl_dump(p, " value 0x%02x", dsmark->cdm_value); + + if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK) + nl_dump(p, " mask 0x%02x", dsmark->cdm_bmask); +} + +static int dsmark_qdisc_msg_fill(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) +{ + struct rtnl_dsmark_qdisc *dsmark = data; + + if (!dsmark) + return 0; + + if (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES) + NLA_PUT_U16(msg, TCA_DSMARK_INDICES, dsmark->qdm_indices); + + if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX) + NLA_PUT_U16(msg, TCA_DSMARK_DEFAULT_INDEX, + dsmark->qdm_default_index); + + if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX) + NLA_PUT_FLAG(msg, TCA_DSMARK_SET_TC_INDEX); + + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +static int dsmark_class_msg_fill(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) +{ + struct rtnl_dsmark_class *dsmark = data; + + if (!dsmark) + return 0; + + if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK) + NLA_PUT_U8(msg, TCA_DSMARK_MASK, dsmark->cdm_bmask); + + if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE) + NLA_PUT_U8(msg, TCA_DSMARK_VALUE, dsmark->cdm_value); + + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +/** + * @name Class Attribute Access + * @{ + */ + +/** + * Set bitmask of DSMARK class. + * @arg class DSMARK class to be modified. + * @arg mask New bitmask. + * @return 0 on success or a negative error code. + */ +int rtnl_class_dsmark_set_bitmask(struct rtnl_class *class, uint8_t mask) +{ + struct rtnl_dsmark_class *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(class)))) + return -NLE_NOMEM; + + dsmark->cdm_bmask = mask; + dsmark->cdm_mask |= SCH_DSMARK_ATTR_MASK; + + return 0; +} + +/** + * Get bitmask of DSMARK class. + * @arg class DSMARK class. + * @return Bitmask or a negative error code. + */ +int rtnl_class_dsmark_get_bitmask(struct rtnl_class *class) +{ + struct rtnl_dsmark_class *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(class)))) + return -NLE_NOMEM; + + if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK) + return dsmark->cdm_bmask; + else + return -NLE_NOATTR; +} + +/** + * Set value of DSMARK class. + * @arg class DSMARK class to be modified. + * @arg value New value. + * @return 0 on success or a negative errror code. + */ +int rtnl_class_dsmark_set_value(struct rtnl_class *class, uint8_t value) +{ + struct rtnl_dsmark_class *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(class)))) + return -NLE_NOMEM; + + dsmark->cdm_value = value; + dsmark->cdm_mask |= SCH_DSMARK_ATTR_VALUE; + + return 0; +} + +/** + * Get value of DSMARK class. + * @arg class DSMARK class. + * @return Value or a negative error code. + */ +int rtnl_class_dsmark_get_value(struct rtnl_class *class) +{ + struct rtnl_dsmark_class *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(class)))) + return -NLE_NOMEM; + + if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE) + return dsmark->cdm_value; + else + return -NLE_NOATTR; +} + +/** @} */ + +/** + * @name Qdisc Attribute Access + * @{ + */ + +/** + * Set indices of DSMARK qdisc. + * @arg qdisc DSMARK qdisc to be modified. + * @arg indices New indices. + */ +int rtnl_qdisc_dsmark_set_indices(struct rtnl_qdisc *qdisc, uint16_t indices) +{ + struct rtnl_dsmark_qdisc *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + dsmark->qdm_indices = indices; + dsmark->qdm_mask |= SCH_DSMARK_ATTR_INDICES; + + return 0; +} + +/** + * Get indices of DSMARK qdisc. + * @arg qdisc DSMARK qdisc. + * @return Indices or a negative error code. + */ +int rtnl_qdisc_dsmark_get_indices(struct rtnl_qdisc *qdisc) +{ + struct rtnl_dsmark_qdisc *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + if (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES) + return dsmark->qdm_indices; + else + return -NLE_NOATTR; +} + +/** + * Set default index of DSMARK qdisc. + * @arg qdisc DSMARK qdisc to be modified. + * @arg default_index New default index. + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_dsmark_set_default_index(struct rtnl_qdisc *qdisc, + uint16_t default_index) +{ + struct rtnl_dsmark_qdisc *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + dsmark->qdm_default_index = default_index; + dsmark->qdm_mask |= SCH_DSMARK_ATTR_DEFAULT_INDEX; + + return 0; +} + +/** + * Get default index of DSMARK qdisc. + * @arg qdisc DSMARK qdisc. + * @return Default index or a negative error code. + */ +int rtnl_qdisc_dsmark_get_default_index(struct rtnl_qdisc *qdisc) +{ + struct rtnl_dsmark_qdisc *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX) + return dsmark->qdm_default_index; + else + return -NLE_NOATTR; +} + +/** + * Set set-tc-index flag of DSMARK qdisc. + * @arg qdisc DSMARK qdisc to be modified. + * @arg flag Flag indicating whether to enable or disable. + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_dsmark_set_set_tc_index(struct rtnl_qdisc *qdisc, int flag) +{ + struct rtnl_dsmark_qdisc *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + dsmark->qdm_set_tc_index = !!flag; + dsmark->qdm_mask |= SCH_DSMARK_ATTR_SET_TC_INDEX; + + return 0; +} + +/** + * Get set-tc-index flag of DSMARK qdisc. + * @arg qdisc DSMARK qdisc to be modified. + * @return 1 or 0 to indicate wehther the flag is enabled or a negative + * error code. + */ +int rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *qdisc) +{ + struct rtnl_dsmark_qdisc *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX) + return dsmark->qdm_set_tc_index; + else + return -NLE_NOATTR; +} + +/** @} */ + +static struct rtnl_tc_ops dsmark_qdisc_ops = { + .to_kind = "dsmark", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_dsmark_qdisc), + .to_msg_parser = dsmark_qdisc_msg_parser, + .to_dump = { + [NL_DUMP_LINE] = dsmark_qdisc_dump_line, + [NL_DUMP_DETAILS] = dsmark_qdisc_dump_details, + }, + .to_msg_fill = dsmark_qdisc_msg_fill, +}; + +static struct rtnl_tc_ops dsmark_class_ops = { + .to_kind = "dsmark", + .to_type = RTNL_TC_TYPE_CLASS, + .to_size = sizeof(struct rtnl_dsmark_class), + .to_msg_parser = dsmark_class_msg_parser, + .to_dump[NL_DUMP_LINE] = dsmark_class_dump_line, + .to_msg_fill = dsmark_class_msg_fill, +}; + +static void __init dsmark_init(void) +{ + rtnl_tc_register(&dsmark_qdisc_ops); + rtnl_tc_register(&dsmark_class_ops); +} + +static void __exit dsmark_exit(void) +{ + rtnl_tc_unregister(&dsmark_qdisc_ops); + rtnl_tc_unregister(&dsmark_class_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/qdisc/fifo.c b/libnetwork/libnl3/lib/route/qdisc/fifo.c new file mode 100644 index 0000000..e87c79a --- /dev/null +++ b/libnetwork/libnl3/lib/route/qdisc/fifo.c @@ -0,0 +1,169 @@ +/* + * lib/route/qdisc/fifo.c (p|b)fifo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +/** + * @ingroup qdisc + * @defgroup qdisc_fifo Packet/Bytes FIFO (pfifo/bfifo) + * @brief + * + * The FIFO qdisc comes in two flavours: + * @par bfifo (Byte FIFO) + * Allows enqueuing until the currently queued volume in bytes exceeds + * the configured limit.backlog contains currently enqueued volume in bytes. + * + * @par pfifo (Packet FIFO) + * Allows enquueing until the currently queued number of packets + * exceeds the configured limit. + * + * The configuration is exactly the same, the decision which of + * the two variations is going to be used is made based on the + * kind of the qdisc (rtnl_tc_set_kind()). + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define SCH_FIFO_ATTR_LIMIT 1 +/** @endcond */ + +static int fifo_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct rtnl_fifo *fifo = data; + struct tc_fifo_qopt *opt; + + if (tc->tc_opts->d_size < sizeof(struct tc_fifo_qopt)) + return -NLE_INVAL; + + opt = (struct tc_fifo_qopt *) tc->tc_opts->d_data; + fifo->qf_limit = opt->limit; + fifo->qf_mask = SCH_FIFO_ATTR_LIMIT; + + return 0; +} + +static void pfifo_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_fifo *fifo = data; + + if (fifo) + nl_dump(p, " limit %u packets", fifo->qf_limit); +} + +static void bfifo_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_fifo *fifo = data; + char *unit; + double r; + + if (!fifo) + return; + + r = nl_cancel_down_bytes(fifo->qf_limit, &unit); + nl_dump(p, " limit %.1f%s", r, unit); +} + +static int fifo_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) +{ + struct rtnl_fifo *fifo = data; + struct tc_fifo_qopt opts = {0}; + + if (!fifo || !(fifo->qf_mask & SCH_FIFO_ATTR_LIMIT)) + return -NLE_INVAL; + + opts.limit = fifo->qf_limit; + + return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD); +} + +/** + * @name Attribute Modification + * @{ + */ + +/** + * Set limit of FIFO qdisc. + * @arg qdisc FIFO qdisc to be modified. + * @arg limit New limit. + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_fifo_set_limit(struct rtnl_qdisc *qdisc, int limit) +{ + struct rtnl_fifo *fifo; + + if (!(fifo = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + fifo->qf_limit = limit; + fifo->qf_mask |= SCH_FIFO_ATTR_LIMIT; + + return 0; +} + +/** + * Get limit of a FIFO qdisc. + * @arg qdisc FIFO qdisc. + * @return Numeric limit or a negative error code. + */ +int rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *qdisc) +{ + struct rtnl_fifo *fifo; + + if (!(fifo = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + if (fifo->qf_mask & SCH_FIFO_ATTR_LIMIT) + return fifo->qf_limit; + else + return -NLE_NOATTR; +} + +/** @} */ + +static struct rtnl_tc_ops pfifo_ops = { + .to_kind = "pfifo", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_fifo), + .to_msg_parser = fifo_msg_parser, + .to_dump[NL_DUMP_LINE] = pfifo_dump_line, + .to_msg_fill = fifo_msg_fill, +}; + +static struct rtnl_tc_ops bfifo_ops = { + .to_kind = "bfifo", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_fifo), + .to_msg_parser = fifo_msg_parser, + .to_dump[NL_DUMP_LINE] = bfifo_dump_line, + .to_msg_fill = fifo_msg_fill, +}; + +static void __init fifo_init(void) +{ + rtnl_tc_register(&pfifo_ops); + rtnl_tc_register(&bfifo_ops); +} + +static void __exit fifo_exit(void) +{ + rtnl_tc_unregister(&pfifo_ops); + rtnl_tc_unregister(&bfifo_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/qdisc/htb.c b/libnetwork/libnl3/lib/route/qdisc/htb.c new file mode 100644 index 0000000..f1d0e75 --- /dev/null +++ b/libnetwork/libnl3/lib/route/qdisc/htb.c @@ -0,0 +1,643 @@ +/* + * lib/route/qdisc/htb.c HTB Qdisc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + * Copyright (c) 2005-2006 Petr Gotthard + * Copyright (c) 2005-2006 Siemens AG Oesterreich + */ + +/** + * @ingroup qdisc + * @ingroup class + * @defgroup qdisc_htb Hierachical Token Bucket (HTB) + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define SCH_HTB_HAS_RATE2QUANTUM 0x01 +#define SCH_HTB_HAS_DEFCLS 0x02 + +#define SCH_HTB_HAS_PRIO 0x001 +#define SCH_HTB_HAS_RATE 0x002 +#define SCH_HTB_HAS_CEIL 0x004 +#define SCH_HTB_HAS_RBUFFER 0x008 +#define SCH_HTB_HAS_CBUFFER 0x010 +#define SCH_HTB_HAS_QUANTUM 0x020 +#define SCH_HTB_HAS_LEVEL 0x040 +/** @endcond */ + +static struct nla_policy htb_policy[TCA_HTB_MAX+1] = { + [TCA_HTB_INIT] = { .minlen = sizeof(struct tc_htb_glob) }, + [TCA_HTB_PARMS] = { .minlen = sizeof(struct tc_htb_opt) }, +}; + +static int htb_qdisc_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct nlattr *tb[TCA_HTB_MAX + 1]; + struct rtnl_htb_qdisc *htb = data; + int err; + + if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0) + return err; + + if (tb[TCA_HTB_INIT]) { + struct tc_htb_glob opts; + + nla_memcpy(&opts, tb[TCA_HTB_INIT], sizeof(opts)); + htb->qh_rate2quantum = opts.rate2quantum; + htb->qh_defcls = opts.defcls; + htb->qh_direct_pkts = opts.direct_pkts; + + htb->qh_mask = (SCH_HTB_HAS_RATE2QUANTUM | SCH_HTB_HAS_DEFCLS); + } + + return 0; +} + +static int htb_class_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct nlattr *tb[TCA_HTB_MAX + 1]; + struct rtnl_htb_class *htb = data; + int err; + + if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0) + return err; + + if (tb[TCA_HTB_PARMS]) { + struct tc_htb_opt opts; + + nla_memcpy(&opts, tb[TCA_HTB_PARMS], sizeof(opts)); + htb->ch_prio = opts.prio; + rtnl_copy_ratespec(&htb->ch_rate, &opts.rate); + rtnl_copy_ratespec(&htb->ch_ceil, &opts.ceil); + htb->ch_rbuffer = rtnl_tc_calc_bufsize(opts.buffer, + opts.rate.rate); + htb->ch_cbuffer = rtnl_tc_calc_bufsize(opts.cbuffer, + opts.ceil.rate); + htb->ch_quantum = opts.quantum; + htb->ch_level = opts.level; + + rtnl_tc_set_mpu(tc, htb->ch_rate.rs_mpu); + rtnl_tc_set_overhead(tc, htb->ch_rate.rs_overhead); + + htb->ch_mask = (SCH_HTB_HAS_PRIO | SCH_HTB_HAS_RATE | + SCH_HTB_HAS_CEIL | SCH_HTB_HAS_RBUFFER | + SCH_HTB_HAS_CBUFFER | SCH_HTB_HAS_QUANTUM | + SCH_HTB_HAS_LEVEL); + } + + return 0; +} + +static void htb_qdisc_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_htb_qdisc *htb = data; + + if (!htb) + return; + + if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM) + nl_dump(p, " r2q %u", htb->qh_rate2quantum); + + if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) { + char buf[64]; + nl_dump(p, " default-class %s", + rtnl_tc_handle2str(htb->qh_defcls, buf, sizeof(buf))); + } +} + +static void htb_class_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_htb_class *htb = data; + + if (!htb) + return; + + if (htb->ch_mask & SCH_HTB_HAS_RATE) { + double r, rbit; + char *ru, *rubit; + + r = nl_cancel_down_bytes(htb->ch_rate.rs_rate, &ru); + rbit = nl_cancel_down_bits(htb->ch_rate.rs_rate*8, &rubit); + + nl_dump(p, " rate %.2f%s/s (%.0f%s) log %u", + r, ru, rbit, rubit, 1<ch_rate.rs_cell_log); + } +} + +static void htb_class_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_htb_class *htb = data; + + if (!htb) + return; + + /* line 1 */ + if (htb->ch_mask & SCH_HTB_HAS_CEIL) { + double r, rbit; + char *ru, *rubit; + + r = nl_cancel_down_bytes(htb->ch_ceil.rs_rate, &ru); + rbit = nl_cancel_down_bits(htb->ch_ceil.rs_rate*8, &rubit); + + nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u", + r, ru, rbit, rubit, 1<ch_ceil.rs_cell_log); + } + + if (htb->ch_mask & SCH_HTB_HAS_PRIO) + nl_dump(p, " prio %u", htb->ch_prio); + + if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) { + double b; + char *bu; + + b = nl_cancel_down_bytes(htb->ch_rbuffer, &bu); + nl_dump(p, " rbuffer %.2f%s", b, bu); + } + + if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) { + double b; + char *bu; + + b = nl_cancel_down_bytes(htb->ch_cbuffer, &bu); + nl_dump(p, " cbuffer %.2f%s", b, bu); + } + + if (htb->ch_mask & SCH_HTB_HAS_QUANTUM) + nl_dump(p, " quantum %u", htb->ch_quantum); +} + +static int htb_qdisc_msg_fill(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) +{ + struct rtnl_htb_qdisc *htb = data; + struct tc_htb_glob opts = {0}; + + opts.version = TC_HTB_PROTOVER; + opts.rate2quantum = 10; + + if (htb) { + if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM) + opts.rate2quantum = htb->qh_rate2quantum; + + if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) + opts.defcls = htb->qh_defcls; + } + + return nla_put(msg, TCA_HTB_INIT, sizeof(opts), &opts); +} + +static int htb_class_msg_fill(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) +{ + struct rtnl_htb_class *htb = data; + uint32_t mtu, rtable[RTNL_TC_RTABLE_SIZE], ctable[RTNL_TC_RTABLE_SIZE]; + struct tc_htb_opt opts; + int buffer, cbuffer; + + if (!htb || !(htb->ch_mask & SCH_HTB_HAS_RATE)) + BUG(); + + memset(&opts, 0, sizeof(opts)); + + /* if not set, zero (0) is used as priority */ + if (htb->ch_mask & SCH_HTB_HAS_PRIO) + opts.prio = htb->ch_prio; + + mtu = rtnl_tc_get_mtu(tc); + + rtnl_tc_build_rate_table(tc, &htb->ch_rate, rtable); + rtnl_rcopy_ratespec(&opts.rate, &htb->ch_rate); + + if (htb->ch_mask & SCH_HTB_HAS_CEIL) { + rtnl_tc_build_rate_table(tc, &htb->ch_ceil, ctable); + rtnl_rcopy_ratespec(&opts.ceil, &htb->ch_ceil); + } else { + /* + * If not set, configured rate is used as ceil, which implies + * no borrowing. + */ + memcpy(&opts.ceil, &opts.rate, sizeof(struct tc_ratespec)); + } + + if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) + buffer = htb->ch_rbuffer; + else + buffer = opts.rate.rate / nl_get_user_hz() + mtu; /* XXX */ + + opts.buffer = rtnl_tc_calc_txtime(buffer, opts.rate.rate); + + if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) + cbuffer = htb->ch_cbuffer; + else + cbuffer = opts.ceil.rate / nl_get_user_hz() + mtu; /* XXX */ + + opts.cbuffer = rtnl_tc_calc_txtime(cbuffer, opts.ceil.rate); + + if (htb->ch_mask & SCH_HTB_HAS_QUANTUM) + opts.quantum = htb->ch_quantum; + + NLA_PUT(msg, TCA_HTB_PARMS, sizeof(opts), &opts); + NLA_PUT(msg, TCA_HTB_RTAB, sizeof(rtable), &rtable); + NLA_PUT(msg, TCA_HTB_CTAB, sizeof(ctable), &ctable); + + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +static struct rtnl_tc_ops htb_qdisc_ops; +static struct rtnl_tc_ops htb_class_ops; + +static struct rtnl_htb_qdisc *htb_qdisc_data(struct rtnl_qdisc *qdisc) +{ + return rtnl_tc_data_check(TC_CAST(qdisc), &htb_qdisc_ops); +} + +static struct rtnl_htb_class *htb_class_data(struct rtnl_class *class) +{ + return rtnl_tc_data_check(TC_CAST(class), &htb_class_ops); +} + +/** + * @name Attribute Modifications + * @{ + */ + +/** + * Return rate/quantum ratio of HTB qdisc + * @arg qdisc htb qdisc object + * + * @return rate/quantum ratio or 0 if unspecified + */ +uint32_t rtnl_htb_get_rate2quantum(struct rtnl_qdisc *qdisc) +{ + struct rtnl_htb_qdisc *htb; + + if ((htb = htb_qdisc_data(qdisc)) && + htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM) + return htb->qh_rate2quantum; + + return 0; +} + +int rtnl_htb_set_rate2quantum(struct rtnl_qdisc *qdisc, uint32_t rate2quantum) +{ + struct rtnl_htb_qdisc *htb; + + if (!(htb = htb_qdisc_data(qdisc))) + return -NLE_OPNOTSUPP; + + htb->qh_rate2quantum = rate2quantum; + htb->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM; + + return 0; +} + +/** + * Return default class of HTB qdisc + * @arg qdisc htb qdisc object + * + * Returns the classid of the class where all unclassified traffic + * goes to. + * + * @return classid or TC_H_UNSPEC if unspecified. + */ +uint32_t rtnl_htb_get_defcls(struct rtnl_qdisc *qdisc) +{ + struct rtnl_htb_qdisc *htb; + + if ((htb = htb_qdisc_data(qdisc)) && + htb->qh_mask & SCH_HTB_HAS_DEFCLS) + return htb->qh_defcls; + + return TC_H_UNSPEC; +} + +/** + * Set default class of the htb qdisc to the specified value + * @arg qdisc qdisc to change + * @arg defcls new default class + */ +int rtnl_htb_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls) +{ + struct rtnl_htb_qdisc *htb; + + if (!(htb = htb_qdisc_data(qdisc))) + return -NLE_OPNOTSUPP; + + htb->qh_defcls = defcls; + htb->qh_mask |= SCH_HTB_HAS_DEFCLS; + + return 0; +} + +uint32_t rtnl_htb_get_prio(struct rtnl_class *class) +{ + struct rtnl_htb_class *htb; + + if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_PRIO) + return htb->ch_prio; + + return 0; +} + +int rtnl_htb_set_prio(struct rtnl_class *class, uint32_t prio) +{ + struct rtnl_htb_class *htb; + + if (!(htb = htb_class_data(class))) + return -NLE_OPNOTSUPP; + + htb->ch_prio = prio; + htb->ch_mask |= SCH_HTB_HAS_PRIO; + + return 0; +} + +/** + * Return rate of HTB class + * @arg class htb class object + * + * @return Rate in bytes/s or 0 if unspecified. + */ +uint32_t rtnl_htb_get_rate(struct rtnl_class *class) +{ + struct rtnl_htb_class *htb; + + if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_RATE) + return htb->ch_rate.rs_rate; + + return 0; +} + +/** + * Set rate of HTB class + * @arg class htb class object + * @arg rate new rate in bytes per second + * + * @return 0 on success or a negative error code. + */ +int rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate) +{ + struct rtnl_htb_class *htb; + + if (!(htb = htb_class_data(class))) + return -NLE_OPNOTSUPP; + + htb->ch_rate.rs_cell_log = UINT8_MAX; /* use default value */ + htb->ch_rate.rs_rate = rate; + htb->ch_mask |= SCH_HTB_HAS_RATE; + + return 0; +} + +/** + * Return ceil rate of HTB class + * @arg class htb class object + * + * @return Ceil rate in bytes/s or 0 if unspecified + */ +uint32_t rtnl_htb_get_ceil(struct rtnl_class *class) +{ + struct rtnl_htb_class *htb; + + if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_CEIL) + return htb->ch_ceil.rs_rate; + + return 0; +} + +/** + * Set ceil rate of HTB class + * @arg class htb class object + * @arg ceil new ceil rate number of bytes per second + * + * @return 0 on success or a negative error code. + */ +int rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil) +{ + struct rtnl_htb_class *htb; + + if (!(htb = htb_class_data(class))) + return -NLE_OPNOTSUPP; + + htb->ch_ceil.rs_cell_log = UINT8_MAX; /* use default value */ + htb->ch_ceil.rs_rate = ceil; + htb->ch_mask |= SCH_HTB_HAS_CEIL; + + return 0; +} + +/** + * Return burst buffer size of HTB class + * @arg class htb class object + * + * @return Burst buffer size or 0 if unspecified + */ +uint32_t rtnl_htb_get_rbuffer(struct rtnl_class *class) +{ + struct rtnl_htb_class *htb; + + if ((htb = htb_class_data(class)) && + htb->ch_mask & SCH_HTB_HAS_RBUFFER) + return htb->ch_rbuffer; + + return 0; +} + +/** + * Set size of the rate bucket of HTB class. + * @arg class HTB class to be modified. + * @arg rbuffer New size in bytes. + */ +int rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t rbuffer) +{ + struct rtnl_htb_class *htb; + + if (!(htb = htb_class_data(class))) + return -NLE_OPNOTSUPP; + + htb->ch_rbuffer = rbuffer; + htb->ch_mask |= SCH_HTB_HAS_RBUFFER; + + return 0; +} + +/** + * Return ceil burst buffer size of HTB class + * @arg class htb class object + * + * @return Ceil burst buffer size or 0 if unspecified + */ +uint32_t rtnl_htb_get_cbuffer(struct rtnl_class *class) +{ + struct rtnl_htb_class *htb; + + if ((htb = htb_class_data(class)) && + htb->ch_mask & SCH_HTB_HAS_CBUFFER) + return htb->ch_cbuffer; + + return 0; +} + +/** + * Set size of the ceil bucket of HTB class. + * @arg class HTB class to be modified. + * @arg cbuffer New size in bytes. + */ +int rtnl_htb_set_cbuffer(struct rtnl_class *class, uint32_t cbuffer) +{ + struct rtnl_htb_class *htb; + + if (!(htb = htb_class_data(class))) + return -NLE_OPNOTSUPP; + + htb->ch_cbuffer = cbuffer; + htb->ch_mask |= SCH_HTB_HAS_CBUFFER; + + return 0; +} + +/** + * Return quantum of HTB class + * @arg class htb class object + * + * See XXX[quantum def] + * + * @return Quantum or 0 if unspecified. + */ +uint32_t rtnl_htb_get_quantum(struct rtnl_class *class) +{ + struct rtnl_htb_class *htb; + + if ((htb = htb_class_data(class)) && + htb->ch_mask & SCH_HTB_HAS_QUANTUM) + return htb->ch_quantum; + + return 0; +} + +/** + * Set quantum of HTB class (overwrites value calculated based on r2q) + * @arg class htb class object + * @arg quantum new quantum in number of bytes + * + * See XXX[quantum def] + * + * @return 0 on success or a negative error code. + */ +int rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum) +{ + struct rtnl_htb_class *htb; + + if (!(htb = htb_class_data(class))) + return -NLE_OPNOTSUPP; + + htb->ch_quantum = quantum; + htb->ch_mask |= SCH_HTB_HAS_QUANTUM; + + return 0; +} + +/** + * Return level of HTB class + * @arg class htb class object + * + * Returns the level of the HTB class. Leaf classes are assigned level + * 0, root classes have level (TC_HTB_MAXDEPTH - 1). Interior classes + * have a level of one less than their parent. + * + * @return Level or -NLE_OPNOTSUPP + */ +int rtnl_htb_get_level(struct rtnl_class *class) +{ + struct rtnl_htb_class *htb; + + if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_LEVEL) + return htb->ch_level; + + return -NLE_OPNOTSUPP; +} + +/** + * Set level of HTB class + * @arg class htb class object + * @arg level new level of HTB class + * + * Sets the level of a HTB class. Note that changing the level of a HTB + * class does not change the level of its in kernel counterpart. This + * function is provided only to create HTB objects which can be compared + * against or filtered upon. + * + * @return 0 on success or a negative error code. + */ +int rtnl_htb_set_level(struct rtnl_class *class, int level) +{ + struct rtnl_htb_class *htb; + + if (!(htb = htb_class_data(class))) + return -NLE_OPNOTSUPP; + + htb->ch_level = level; + htb->ch_mask |= SCH_HTB_HAS_LEVEL; + + return 0; +} + +/** @} */ + +static struct rtnl_tc_ops htb_qdisc_ops = { + .to_kind = "htb", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_htb_qdisc), + .to_msg_parser = htb_qdisc_msg_parser, + .to_dump[NL_DUMP_LINE] = htb_qdisc_dump_line, + .to_msg_fill = htb_qdisc_msg_fill, +}; + +static struct rtnl_tc_ops htb_class_ops = { + .to_kind = "htb", + .to_type = RTNL_TC_TYPE_CLASS, + .to_size = sizeof(struct rtnl_htb_class), + .to_msg_parser = htb_class_msg_parser, + .to_dump = { + [NL_DUMP_LINE] = htb_class_dump_line, + [NL_DUMP_DETAILS] = htb_class_dump_details, + }, + .to_msg_fill = htb_class_msg_fill, +}; + +static void __init htb_init(void) +{ + rtnl_tc_register(&htb_qdisc_ops); + rtnl_tc_register(&htb_class_ops); +} + +static void __exit htb_exit(void) +{ + rtnl_tc_unregister(&htb_qdisc_ops); + rtnl_tc_unregister(&htb_class_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/qdisc/netem.c b/libnetwork/libnl3/lib/route/qdisc/netem.c new file mode 100644 index 0000000..997a31f --- /dev/null +++ b/libnetwork/libnl3/lib/route/qdisc/netem.c @@ -0,0 +1,906 @@ +/* + * lib/route/qdisc/netem.c Network Emulator Qdisc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +/** + * @ingroup qdisc + * @defgroup qdisc_netem Network Emulator + * @brief + * + * For further documentation see http://linux-net.osdl.org/index.php/Netem + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define SCH_NETEM_ATTR_LATENCY 0x0001 +#define SCH_NETEM_ATTR_LIMIT 0x0002 +#define SCH_NETEM_ATTR_LOSS 0x0004 +#define SCH_NETEM_ATTR_GAP 0x0008 +#define SCH_NETEM_ATTR_DUPLICATE 0x0010 +#define SCH_NETEM_ATTR_JITTER 0x0020 +#define SCH_NETEM_ATTR_DELAY_CORR 0x0040 +#define SCH_NETEM_ATTR_LOSS_CORR 0x0080 +#define SCH_NETEM_ATTR_DUP_CORR 0x0100 +#define SCH_NETEM_ATTR_RO_PROB 0x0200 +#define SCH_NETEM_ATTR_RO_CORR 0x0400 +#define SCH_NETEM_ATTR_CORRUPT_PROB 0x0800 +#define SCH_NETEM_ATTR_CORRUPT_CORR 0x1000 +#define SCH_NETEM_ATTR_DIST 0x2000 +/** @endcond */ + +static struct nla_policy netem_policy[TCA_NETEM_MAX+1] = { + [TCA_NETEM_CORR] = { .minlen = sizeof(struct tc_netem_corr) }, + [TCA_NETEM_REORDER] = { .minlen = sizeof(struct tc_netem_reorder) }, + [TCA_NETEM_CORRUPT] = { .minlen = sizeof(struct tc_netem_corrupt) }, +}; + +static int netem_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct rtnl_netem *netem = data; + struct tc_netem_qopt *opts; + int len, err = 0; + + if (tc->tc_opts->d_size < sizeof(*opts)) + return -NLE_INVAL; + + opts = (struct tc_netem_qopt *) tc->tc_opts->d_data; + netem->qnm_latency = opts->latency; + netem->qnm_limit = opts->limit; + netem->qnm_loss = opts->loss; + netem->qnm_gap = opts->gap; + netem->qnm_duplicate = opts->duplicate; + netem->qnm_jitter = opts->jitter; + + netem->qnm_mask = (SCH_NETEM_ATTR_LATENCY | SCH_NETEM_ATTR_LIMIT | + SCH_NETEM_ATTR_LOSS | SCH_NETEM_ATTR_GAP | + SCH_NETEM_ATTR_DUPLICATE | SCH_NETEM_ATTR_JITTER); + + len = tc->tc_opts->d_size - sizeof(*opts); + + if (len > 0) { + struct nlattr *tb[TCA_NETEM_MAX+1]; + + err = nla_parse(tb, TCA_NETEM_MAX, (struct nlattr *) + (tc->tc_opts->d_data + sizeof(*opts)), + len, netem_policy); + if (err < 0) { + free(netem); + return err; + } + + if (tb[TCA_NETEM_CORR]) { + struct tc_netem_corr cor; + + nla_memcpy(&cor, tb[TCA_NETEM_CORR], sizeof(cor)); + netem->qnm_corr.nmc_delay = cor.delay_corr; + netem->qnm_corr.nmc_loss = cor.loss_corr; + netem->qnm_corr.nmc_duplicate = cor.dup_corr; + + netem->qnm_mask |= (SCH_NETEM_ATTR_DELAY_CORR | + SCH_NETEM_ATTR_LOSS_CORR | + SCH_NETEM_ATTR_DUP_CORR); + } + + if (tb[TCA_NETEM_REORDER]) { + struct tc_netem_reorder ro; + + nla_memcpy(&ro, tb[TCA_NETEM_REORDER], sizeof(ro)); + netem->qnm_ro.nmro_probability = ro.probability; + netem->qnm_ro.nmro_correlation = ro.correlation; + + netem->qnm_mask |= (SCH_NETEM_ATTR_RO_PROB | + SCH_NETEM_ATTR_RO_CORR); + } + + if (tb[TCA_NETEM_CORRUPT]) { + struct tc_netem_corrupt corrupt; + + nla_memcpy(&corrupt, tb[TCA_NETEM_CORRUPT], sizeof(corrupt)); + netem->qnm_crpt.nmcr_probability = corrupt.probability; + netem->qnm_crpt.nmcr_correlation = corrupt.correlation; + + netem->qnm_mask |= (SCH_NETEM_ATTR_CORRUPT_PROB | + SCH_NETEM_ATTR_CORRUPT_CORR); + } + + /* sch_netem does not currently dump TCA_NETEM_DELAY_DIST */ + netem->qnm_dist.dist_data = NULL; + netem->qnm_dist.dist_size = 0; + } + + return 0; +} + +static void netem_free_data(struct rtnl_tc *tc, void *data) +{ + struct rtnl_netem *netem = data; + + if (!netem) + return; + + free(netem->qnm_dist.dist_data); +} + +static void netem_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_netem *netem = data; + + if (netem) + nl_dump(p, "limit %d", netem->qnm_limit); +} + +static int netem_msg_fill_raw(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) +{ + int err = 0; + struct tc_netem_qopt opts; + struct tc_netem_corr cor; + struct tc_netem_reorder reorder; + struct tc_netem_corrupt corrupt; + struct rtnl_netem *netem = data; + + unsigned char set_correlation = 0, set_reorder = 0, + set_corrupt = 0, set_dist = 0; + + if (!netem) + BUG(); + + memset(&opts, 0, sizeof(opts)); + memset(&cor, 0, sizeof(cor)); + memset(&reorder, 0, sizeof(reorder)); + memset(&corrupt, 0, sizeof(corrupt)); + + msg->nm_nlh->nlmsg_flags |= NLM_F_REQUEST; + + if ( netem->qnm_ro.nmro_probability != 0 ) { + if (netem->qnm_latency == 0) { + return -NLE_MISSING_ATTR; + } + if (netem->qnm_gap == 0) netem->qnm_gap = 1; + } + else if ( netem->qnm_gap ) { + return -NLE_MISSING_ATTR; + } + + if ( netem->qnm_corr.nmc_delay != 0 ) { + if ( netem->qnm_latency == 0 || netem->qnm_jitter == 0) { + return -NLE_MISSING_ATTR; + } + set_correlation = 1; + } + + if ( netem->qnm_corr.nmc_loss != 0 ) { + if ( netem->qnm_loss == 0 ) { + return -NLE_MISSING_ATTR; + } + set_correlation = 1; + } + + if ( netem->qnm_corr.nmc_duplicate != 0 ) { + if ( netem->qnm_duplicate == 0 ) { + return -NLE_MISSING_ATTR; + } + set_correlation = 1; + } + + if ( netem->qnm_ro.nmro_probability != 0 ) set_reorder = 1; + else if ( netem->qnm_ro.nmro_correlation != 0 ) { + return -NLE_MISSING_ATTR; + } + + if ( netem->qnm_crpt.nmcr_probability != 0 ) set_corrupt = 1; + else if ( netem->qnm_crpt.nmcr_correlation != 0 ) { + return -NLE_MISSING_ATTR; + } + + if ( netem->qnm_dist.dist_data && netem->qnm_dist.dist_size ) { + if (netem->qnm_latency == 0 || netem->qnm_jitter == 0) { + return -NLE_MISSING_ATTR; + } + else { + /* Resize to accomodate the large distribution table */ + int new_msg_len = msg->nm_size + netem->qnm_dist.dist_size * + sizeof(netem->qnm_dist.dist_data[0]); + + msg->nm_nlh = (struct nlmsghdr *) realloc(msg->nm_nlh, new_msg_len); + if ( msg->nm_nlh == NULL ) + return -NLE_NOMEM; + msg->nm_size = new_msg_len; + set_dist = 1; + } + } + + opts.latency = netem->qnm_latency; + opts.limit = netem->qnm_limit ? netem->qnm_limit : 1000; + opts.loss = netem->qnm_loss; + opts.gap = netem->qnm_gap; + opts.duplicate = netem->qnm_duplicate; + opts.jitter = netem->qnm_jitter; + + NLA_PUT(msg, TCA_OPTIONS, sizeof(opts), &opts); + + if ( set_correlation ) { + cor.delay_corr = netem->qnm_corr.nmc_delay; + cor.loss_corr = netem->qnm_corr.nmc_loss; + cor.dup_corr = netem->qnm_corr.nmc_duplicate; + + NLA_PUT(msg, TCA_NETEM_CORR, sizeof(cor), &cor); + } + + if ( set_reorder ) { + reorder.probability = netem->qnm_ro.nmro_probability; + reorder.correlation = netem->qnm_ro.nmro_correlation; + + NLA_PUT(msg, TCA_NETEM_REORDER, sizeof(reorder), &reorder); + } + + if ( set_corrupt ) { + corrupt.probability = netem->qnm_crpt.nmcr_probability; + corrupt.correlation = netem->qnm_crpt.nmcr_correlation; + + NLA_PUT(msg, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt); + } + + if ( set_dist ) { + NLA_PUT(msg, TCA_NETEM_DELAY_DIST, + netem->qnm_dist.dist_size * sizeof(netem->qnm_dist.dist_data[0]), + netem->qnm_dist.dist_data); + } + + /* Length specified in the TCA_OPTIONS section must span the entire + * remainder of the message. That's just the way that sch_netem expects it. + * Maybe there's a more succinct way to do this at a higher level. + */ + struct nlattr* head = (struct nlattr *)(NLMSG_DATA(msg->nm_nlh) + + NLMSG_LENGTH(sizeof(struct tcmsg)) - NLMSG_ALIGNTO); + + struct nlattr* tail = (struct nlattr *)(((void *) (msg->nm_nlh)) + + NLMSG_ALIGN(msg->nm_nlh->nlmsg_len)); + + int old_len = head->nla_len; + head->nla_len = (void *)tail - (void *)head; + msg->nm_nlh->nlmsg_len += (head->nla_len - old_len); + + return err; +nla_put_failure: + return -NLE_MSGSIZE; +} + +/** + * @name Queue Limit + * @{ + */ + +/** + * Set limit of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg limit New limit in bytes. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_limit(struct rtnl_qdisc *qdisc, int limit) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_limit = limit; + netem->qnm_mask |= SCH_NETEM_ATTR_LIMIT; +} + +/** + * Get limit of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Limit in bytes or a negative error code. + */ +int rtnl_netem_get_limit(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + if (netem->qnm_mask & SCH_NETEM_ATTR_LIMIT) + return netem->qnm_limit; + else + return -NLE_NOATTR; +} + +/** @} */ + +/** + * @name Packet Re-ordering + * @{ + */ + +/** + * Set re-ordering gap of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg gap New gap in number of packets. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_gap(struct rtnl_qdisc *qdisc, int gap) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_gap = gap; + netem->qnm_mask |= SCH_NETEM_ATTR_GAP; +} + +/** + * Get re-ordering gap of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Re-ordering gap in packets or a negative error code. + */ +int rtnl_netem_get_gap(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + if (netem->qnm_mask & SCH_NETEM_ATTR_GAP) + return netem->qnm_gap; + else + return -NLE_NOATTR; +} + +/** + * Set re-ordering probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New re-ordering probability. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_reorder_probability(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_ro.nmro_probability = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_RO_PROB; +} + +/** + * Get re-ordering probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Re-ordering probability or a negative error code. + */ +int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + if (netem->qnm_mask & SCH_NETEM_ATTR_RO_PROB) + return netem->qnm_ro.nmro_probability; + else + return -NLE_NOATTR; +} + +/** + * Set re-order correlation probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New re-ordering correlation probability. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_ro.nmro_correlation = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_RO_CORR; +} + +/** + * Get re-ordering correlation probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Re-ordering correlation probability or a negative error code. + */ +int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + if (netem->qnm_mask & SCH_NETEM_ATTR_RO_CORR) + return netem->qnm_ro.nmro_correlation; + else + return -NLE_NOATTR; +} + +/** @} */ + +/** + * @name Corruption + * @{ + */ + +/** + * Set corruption probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New corruption probability. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_corruption_probability(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_crpt.nmcr_probability = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_PROB; +} + +/** + * Get corruption probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Corruption probability or a negative error code. + */ +int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_PROB) + return netem->qnm_crpt.nmcr_probability; + else + return -NLE_NOATTR; +} + +/** + * Set corruption correlation probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New corruption correlation probability. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_crpt.nmcr_correlation = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_CORR; +} + +/** + * Get corruption correlation probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Corruption correlation probability or a negative error code. + */ +int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_CORR) + return netem->qnm_crpt.nmcr_correlation; + else + return -NLE_NOATTR; +} + +/** @} */ + +/** + * @name Packet Loss + * @{ + */ + +/** + * Set packet loss probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New packet loss probability. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_loss(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_loss = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_LOSS; +} + +/** + * Get packet loss probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Packet loss probability or a negative error code. + */ +int rtnl_netem_get_loss(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS) + return netem->qnm_loss; + else + return -NLE_NOATTR; +} + +/** + * Set packet loss correlation probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New packet loss correlation. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_loss_correlation(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_corr.nmc_loss = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_LOSS_CORR; +} + +/** + * Get packet loss correlation probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Packet loss correlation probability or a negative error code. + */ +int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS_CORR) + return netem->qnm_corr.nmc_loss; + else + return -NLE_NOATTR; +} + +/** @} */ + +/** + * @name Packet Duplication + * @{ + */ + +/** + * Set packet duplication probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New packet duplication probability. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_duplicate(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_duplicate = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_DUPLICATE; +} + +/** + * Get packet duplication probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Packet duplication probability or a negative error code. + */ +int rtnl_netem_get_duplicate(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_DUPLICATE) + return netem->qnm_duplicate; + else + return -NLE_NOATTR; +} + +/** + * Set packet duplication correlation probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New packet duplication correlation probability. + * @return 0 on sucess or a negative error code. + */ +void rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_corr.nmc_duplicate = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_DUP_CORR; +} + +/** + * Get packet duplication correlation probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Packet duplication correlation probability or a negative error code. + */ +int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_DUP_CORR) + return netem->qnm_corr.nmc_duplicate; + else + return -NLE_NOATTR; +} + +/** @} */ + +/** + * @name Packet Delay + * @{ + */ + +/** + * Set packet delay of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg delay New packet delay in micro seconds. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_delay(struct rtnl_qdisc *qdisc, int delay) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_latency = nl_us2ticks(delay); + netem->qnm_mask |= SCH_NETEM_ATTR_LATENCY; +} + +/** + * Get packet delay of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Packet delay in micro seconds or a negative error code. + */ +int rtnl_netem_get_delay(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_LATENCY) + return nl_ticks2us(netem->qnm_latency); + else + return -NLE_NOATTR; +} + +/** + * Set packet delay jitter of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg jitter New packet delay jitter in micro seconds. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_jitter(struct rtnl_qdisc *qdisc, int jitter) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_jitter = nl_us2ticks(jitter); + netem->qnm_mask |= SCH_NETEM_ATTR_JITTER; +} + +/** + * Get packet delay jitter of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Packet delay jitter in micro seconds or a negative error code. + */ +int rtnl_netem_get_jitter(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_JITTER) + return nl_ticks2us(netem->qnm_jitter); + else + return -NLE_NOATTR; +} + +/** + * Set packet delay correlation probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New packet delay correlation probability. + */ +void rtnl_netem_set_delay_correlation(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_corr.nmc_delay = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_DELAY_CORR; +} + +/** + * Get packet delay correlation probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Packet delay correlation probability or a negative error code. + */ +int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_DELAY_CORR) + return netem->qnm_corr.nmc_delay; + else + return -NLE_NOATTR; +} + +/** + * Get the size of the distribution table. + * @arg qdisc Netem qdisc. + * @return Distribution table size or a negative error code. + */ +int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_DIST) + return netem->qnm_dist.dist_size; + else + return -NLE_NOATTR; +} + +/** + * Get a pointer to the distribution table. + * @arg qdisc Netem qdisc. + * @arg dist_ptr The pointer to set. + * @return Negative error code on failure or 0 on success. + */ +int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *qdisc, int16_t **dist_ptr) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_DIST) { + *dist_ptr = netem->qnm_dist.dist_data; + return 0; + } else + return -NLE_NOATTR; +} + +/** + * Set the delay distribution. Latency/jitter must be set before applying. + * @arg qdisc Netem qdisc. + * @arg dist_type The name of the distribution (type, file, path/file). + * @return 0 on success, error code on failure. + */ +int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist_type) { + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + FILE *f = NULL; + int i, n = 0; + size_t len = 2048; + char *line; + char name[NAME_MAX]; + char dist_suffix[] = ".dist"; + + /* If the given filename already ends in .dist, don't append it later */ + char *test_suffix = strstr(dist_type, dist_suffix); + if (test_suffix != NULL && strlen(test_suffix) == 5) + strcpy(dist_suffix, ""); + + /* Check several locations for the dist file */ + char *test_path[] = { "", "./", "/usr/lib/tc/", "/usr/local/lib/tc/" }; + + for (i = 0; i < sizeof(test_path) && f == NULL; i++) { + snprintf(name, NAME_MAX, "%s%s%s", test_path[i], dist_type, dist_suffix); + f = fopen(name, "r"); + } + + if ( f == NULL ) + return -nl_syserr2nlerr(errno); + + netem->qnm_dist.dist_data = (int16_t *) calloc (MAXDIST, sizeof(int16_t)); + + line = (char *) calloc (sizeof(char), len + 1); + + while (getline(&line, &len, f) != -1) { + char *p, *endp; + + if (*line == '\n' || *line == '#') + continue; + + for (p = line; ; p = endp) { + long x = strtol(p, &endp, 0); + if (endp == p) break; + + if (n >= MAXDIST) { + free(line); + fclose(f); + return -NLE_INVAL; + } + netem->qnm_dist.dist_data[n++] = x; + } + } + + free(line); + + netem->qnm_dist.dist_size = n; + netem->qnm_mask |= SCH_NETEM_ATTR_DIST; + + fclose(f); + return 0; +} + +/** @} */ + +static struct rtnl_tc_ops netem_ops = { + .to_kind = "netem", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_netem), + .to_msg_parser = netem_msg_parser, + .to_free_data = netem_free_data, + .to_dump[NL_DUMP_LINE] = netem_dump_line, + .to_msg_fill_raw = netem_msg_fill_raw, +}; + +static void __init netem_init(void) +{ + rtnl_tc_register(&netem_ops); +} + +static void __exit netem_exit(void) +{ + rtnl_tc_unregister(&netem_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/qdisc/prio.c b/libnetwork/libnl3/lib/route/qdisc/prio.c new file mode 100644 index 0000000..2433c61 --- /dev/null +++ b/libnetwork/libnl3/lib/route/qdisc/prio.c @@ -0,0 +1,294 @@ +/* + * lib/route/qdisc/prio.c PRIO Qdisc/Class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +/** + * @ingroup qdisc + * @defgroup qdisc_prio (Fast) Prio + * @brief + * + * @par 1) Typical PRIO configuration + * @code + * // Specify the maximal number of bands to be used for this PRIO qdisc. + * rtnl_qdisc_prio_set_bands(qdisc, QDISC_PRIO_DEFAULT_BANDS); + * + * // Provide a map assigning each priority to a band number. + * uint8_t map[] = QDISC_PRIO_DEFAULT_PRIOMAP; + * rtnl_qdisc_prio_set_priomap(qdisc, map, sizeof(map)); + * @endcode + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define SCH_PRIO_ATTR_BANDS 1 +#define SCH_PRIO_ATTR_PRIOMAP 2 +/** @endcond */ + +static int prio_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct rtnl_prio *prio = data; + struct tc_prio_qopt *opt; + + if (tc->tc_opts->d_size < sizeof(*opt)) + return -NLE_INVAL; + + opt = (struct tc_prio_qopt *) tc->tc_opts->d_data; + prio->qp_bands = opt->bands; + memcpy(prio->qp_priomap, opt->priomap, sizeof(prio->qp_priomap)); + prio->qp_mask = (SCH_PRIO_ATTR_BANDS | SCH_PRIO_ATTR_PRIOMAP); + + return 0; +} + +static void prio_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_prio *prio = data; + + if (prio) + nl_dump(p, " bands %u", prio->qp_bands); +} + +static void prio_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_prio *prio = data; + int i, hp; + + if (!prio) + return; + + nl_dump(p, "priomap ["); + + for (i = 0; i <= TC_PRIO_MAX; i++) + nl_dump(p, "%u%s", prio->qp_priomap[i], + i < TC_PRIO_MAX ? " " : ""); + + nl_dump(p, "]\n"); + nl_new_line(p); + + hp = (((TC_PRIO_MAX/2) + 1) & ~1); + + for (i = 0; i < hp; i++) { + char a[32]; + nl_dump(p, " %18s => %u", + rtnl_prio2str(i, a, sizeof(a)), + prio->qp_priomap[i]); + if (hp+i <= TC_PRIO_MAX) { + nl_dump(p, " %18s => %u", + rtnl_prio2str(hp+i, a, sizeof(a)), + prio->qp_priomap[hp+i]); + if (i < (hp - 1)) { + nl_dump(p, "\n"); + nl_new_line(p); + } + } + } +} + +static int prio_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) +{ + struct rtnl_prio *prio = data; + struct tc_prio_qopt opts; + + if (!prio || !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)) + BUG(); + + opts.bands = prio->qp_bands; + memcpy(opts.priomap, prio->qp_priomap, sizeof(opts.priomap)); + + return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD); +} + +/** + * @name Attribute Modification + * @{ + */ + +/** + * Set number of bands of PRIO qdisc. + * @arg qdisc PRIO qdisc to be modified. + * @arg bands New number of bands. + * @return 0 on success or a negative error code. + */ +void rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands) +{ + struct rtnl_prio *prio; + + if (!(prio = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + prio->qp_bands = bands; + prio->qp_mask |= SCH_PRIO_ATTR_BANDS; +} + +/** + * Get number of bands of PRIO qdisc. + * @arg qdisc PRIO qdisc. + * @return Number of bands or a negative error code. + */ +int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc) +{ + struct rtnl_prio *prio; + + if (!(prio = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (prio->qp_mask & SCH_PRIO_ATTR_BANDS) + return prio->qp_bands; + else + return -NLE_NOMEM; +} + +/** + * Set priomap of the PRIO qdisc. + * @arg qdisc PRIO qdisc to be modified. + * @arg priomap New priority mapping. + * @arg len Length of priomap (# of elements). + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[], + int len) +{ + struct rtnl_prio *prio; + int i; + + if (!(prio = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS)) + return -NLE_MISSING_ATTR; + + if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1)) + return -NLE_RANGE; + + for (i = 0; i <= TC_PRIO_MAX; i++) { + if (priomap[i] > prio->qp_bands) + return -NLE_RANGE; + } + + memcpy(prio->qp_priomap, priomap, len); + prio->qp_mask |= SCH_PRIO_ATTR_PRIOMAP; + + return 0; +} + +/** + * Get priomap of a PRIO qdisc. + * @arg qdisc PRIO qdisc. + * @return Priority mapping as array of size TC_PRIO_MAX+1 + * or NULL if an error occured. + */ +uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc) +{ + struct rtnl_prio *prio; + + if (!(prio = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP) + return prio->qp_priomap; + else + return NULL; +} + +/** @} */ + +/** + * @name Priority Band Translations + * @{ + */ + +static const struct trans_tbl prios[] = { + __ADD(TC_PRIO_BESTEFFORT,besteffort) + __ADD(TC_PRIO_FILLER,filler) + __ADD(TC_PRIO_BULK,bulk) + __ADD(TC_PRIO_INTERACTIVE_BULK,interactive_bulk) + __ADD(TC_PRIO_INTERACTIVE,interactive) + __ADD(TC_PRIO_CONTROL,control) +}; + +/** + * Convert priority to character string. + * @arg prio Priority. + * @arg buf Destination buffer + * @arg size Size of destination buffer. + * + * Converts a priority to a character string and stores the result in + * the specified destination buffer. + * + * @return Name of priority as character string. + */ +char * rtnl_prio2str(int prio, char *buf, size_t size) +{ + return __type2str(prio, buf, size, prios, ARRAY_SIZE(prios)); +} + +/** + * Convert character string to priority. + * @arg name Name of priority. + * + * Converts the provided character string specifying a priority + * to the corresponding numeric value. + * + * @return Numeric priority or a negative value if no match was found. + */ +int rtnl_str2prio(const char *name) +{ + return __str2type(name, prios, ARRAY_SIZE(prios)); +} + +/** @} */ + +static struct rtnl_tc_ops prio_ops = { + .to_kind = "prio", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_prio), + .to_msg_parser = prio_msg_parser, + .to_dump = { + [NL_DUMP_LINE] = prio_dump_line, + [NL_DUMP_DETAILS] = prio_dump_details, + }, + .to_msg_fill = prio_msg_fill, +}; + +static struct rtnl_tc_ops pfifo_fast_ops = { + .to_kind = "pfifo_fast", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_prio), + .to_msg_parser = prio_msg_parser, + .to_dump = { + [NL_DUMP_LINE] = prio_dump_line, + [NL_DUMP_DETAILS] = prio_dump_details, + }, + .to_msg_fill = prio_msg_fill, +}; + +static void __init prio_init(void) +{ + rtnl_tc_register(&prio_ops); + rtnl_tc_register(&pfifo_fast_ops); +} + +static void __exit prio_exit(void) +{ + rtnl_tc_unregister(&prio_ops); + rtnl_tc_unregister(&pfifo_fast_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/qdisc/red.c b/libnetwork/libnl3/lib/route/qdisc/red.c new file mode 100644 index 0000000..0480282 --- /dev/null +++ b/libnetwork/libnl3/lib/route/qdisc/red.c @@ -0,0 +1,190 @@ +/* + * lib/route/qdisc/red.c RED Qdisc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +/** + * @ingroup qdisc + * @defgroup qdisc_red Random Early Detection (RED) + * @brief + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define RED_ATTR_LIMIT 0x01 +#define RED_ATTR_QTH_MIN 0x02 +#define RED_ATTR_QTH_MAX 0x04 +#define RED_ATTR_FLAGS 0x08 +#define RED_ATTR_WLOG 0x10 +#define RED_ATTR_PLOG 0x20 +#define RED_ATTR_SCELL_LOG 0x40 +/** @endcond */ + +static struct nla_policy red_policy[TCA_RED_MAX+1] = { + [TCA_RED_PARMS] = { .minlen = sizeof(struct tc_red_qopt) }, +}; + +static int red_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct nlattr *tb[TCA_RED_MAX+1]; + struct rtnl_red *red = data; + struct tc_red_qopt *opts; + int err; + + if (!(tc->ce_mask & TCA_ATTR_OPTS)) + return 0; + + err = tca_parse(tb, TCA_RED_MAX, tc, red_policy); + if (err < 0) + return err; + + if (!tb[TCA_RED_PARMS]) + return -NLE_MISSING_ATTR; + + opts = nla_data(tb[TCA_RED_PARMS]); + + red->qr_limit = opts->limit; + red->qr_qth_min = opts->qth_min; + red->qr_qth_max = opts->qth_max; + red->qr_flags = opts->flags; + red->qr_wlog = opts->Wlog; + red->qr_plog = opts->Plog; + red->qr_scell_log = opts->Scell_log; + + red->qr_mask = (RED_ATTR_LIMIT | RED_ATTR_QTH_MIN | RED_ATTR_QTH_MAX | + RED_ATTR_FLAGS | RED_ATTR_WLOG | RED_ATTR_PLOG | + RED_ATTR_SCELL_LOG); + + return 0; +} + +static void red_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_red *red = data; + + if (red) { + /* XXX: limit, min, max, flags */ + } +} + +static void red_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_red *red = data; + + if (red) { + /* XXX: wlog, plog, scell_log */ + } +} + +static void red_dump_stats(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_red *red = data; + + if (red) { + /* XXX: xstats */ + } +} + +static int red_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) +{ + struct rtnl_red *red = data; + + if (!red) + BUG(); + +#if 0 + memset(&opts, 0, sizeof(opts)); + opts.quantum = sfq->qs_quantum; + opts.perturb_period = sfq->qs_perturb; + opts.limit = sfq->qs_limit; + + if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0) + goto errout; +#endif + + return -NLE_OPNOTSUPP; +} + +/** + * @name Attribute Access + * @{ + */ + +/** + * Set limit of RED qdisc. + * @arg qdisc RED qdisc to be modified. + * @arg limit New limit in number of packets. + * @return 0 on success or a negative error code. + */ +void rtnl_red_set_limit(struct rtnl_qdisc *qdisc, int limit) +{ + struct rtnl_red *red; + + if (!(red = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + red->qr_limit = limit; + red->qr_mask |= RED_ATTR_LIMIT; +} + +/** + * Get limit of RED qdisc. + * @arg qdisc RED qdisc. + * @return Limit or a negative error code. + */ +int rtnl_red_get_limit(struct rtnl_qdisc *qdisc) +{ + struct rtnl_red *red; + + if (!(red = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (red->qr_mask & RED_ATTR_LIMIT) + return red->qr_limit; + else + return -NLE_NOATTR; +} + +/** @} */ + +static struct rtnl_tc_ops red_ops = { + .to_kind = "red", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_red), + .to_msg_parser = red_msg_parser, + .to_dump = { + [NL_DUMP_LINE] = red_dump_line, + [NL_DUMP_DETAILS] = red_dump_details, + [NL_DUMP_STATS] = red_dump_stats, + }, + .to_msg_fill = red_msg_fill, +}; + +static void __init red_init(void) +{ + rtnl_tc_register(&red_ops); +} + +static void __exit red_exit(void) +{ + rtnl_tc_unregister(&red_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/qdisc/sfq.c b/libnetwork/libnl3/lib/route/qdisc/sfq.c new file mode 100644 index 0000000..207140f --- /dev/null +++ b/libnetwork/libnl3/lib/route/qdisc/sfq.c @@ -0,0 +1,256 @@ +/* + * lib/route/qdisc/sfq.c SFQ Qdisc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +/** + * @ingroup qdisc + * @defgroup qdisc_sfq Stochastic Fairness Queueing (SFQ) + * @brief + * + * @par Parameter Description + * - \b Quantum: Number of bytes to send out per slot and round. + * - \b Perturbation: Timer period between changing the hash function. + * - \b Limit: Upper limit of queue in number of packets before SFQ starts + * dropping packets. + * - \b Divisor: Hash table divisor, i.e. size of hash table. + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define SCH_SFQ_ATTR_QUANTUM 0x01 +#define SCH_SFQ_ATTR_PERTURB 0x02 +#define SCH_SFQ_ATTR_LIMIT 0x04 +#define SCH_SFQ_ATTR_DIVISOR 0x08 +#define SCH_SFQ_ATTR_FLOWS 0x10 +/** @endcond */ + +static int sfq_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct rtnl_sfq *sfq = data; + struct tc_sfq_qopt *opts; + + if (!(tc->ce_mask & TCA_ATTR_OPTS)) + return 0; + + if (tc->tc_opts->d_size < sizeof(*opts)) + return -NLE_INVAL; + + opts = (struct tc_sfq_qopt *) tc->tc_opts->d_data; + + sfq->qs_quantum = opts->quantum; + sfq->qs_perturb = opts->perturb_period; + sfq->qs_limit = opts->limit; + sfq->qs_divisor = opts->divisor; + sfq->qs_flows = opts->flows; + + sfq->qs_mask = (SCH_SFQ_ATTR_QUANTUM | SCH_SFQ_ATTR_PERTURB | + SCH_SFQ_ATTR_LIMIT | SCH_SFQ_ATTR_DIVISOR | + SCH_SFQ_ATTR_FLOWS); + + return 0; +} + +static void sfq_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_sfq *sfq = data; + + if (sfq) + nl_dump(p, " quantum %u perturb %us", sfq->qs_quantum, + sfq->qs_perturb); +} + +static void sfq_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_sfq *sfq = data; + + if (sfq) + nl_dump(p, "limit %u divisor %u", + sfq->qs_limit, sfq->qs_divisor); +} + +static int sfq_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) +{ + struct rtnl_sfq *sfq = data; + struct tc_sfq_qopt opts = {0}; + + if (!sfq) + BUG(); + + opts.quantum = sfq->qs_quantum; + opts.perturb_period = sfq->qs_perturb; + opts.limit = sfq->qs_limit; + + return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD); +} + +/** + * @name Attribute Access + * @{ + */ + +/** + * Set quantum of SFQ qdisc. + * @arg qdisc SFQ qdisc to be modified. + * @arg quantum New quantum in bytes. + * @return 0 on success or a negative error code. + */ +void rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum) +{ + struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + sfq->qs_quantum = quantum; + sfq->qs_mask |= SCH_SFQ_ATTR_QUANTUM; +} + +/** + * Get quantum of SFQ qdisc. + * @arg qdisc SFQ qdisc. + * @return Quantum in bytes or a negative error code. + */ +int rtnl_sfq_get_quantum(struct rtnl_qdisc *qdisc) +{ + struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (sfq->qs_mask & SCH_SFQ_ATTR_QUANTUM) + return sfq->qs_quantum; + else + return -NLE_NOATTR; +} + +/** + * Set limit of SFQ qdisc. + * @arg qdisc SFQ qdisc to be modified. + * @arg limit New limit in number of packets. + * @return 0 on success or a negative error code. + */ +void rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit) +{ + struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + sfq->qs_limit = limit; + sfq->qs_mask |= SCH_SFQ_ATTR_LIMIT; +} + +/** + * Get limit of SFQ qdisc. + * @arg qdisc SFQ qdisc. + * @return Limit or a negative error code. + */ +int rtnl_sfq_get_limit(struct rtnl_qdisc *qdisc) +{ + struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (sfq->qs_mask & SCH_SFQ_ATTR_LIMIT) + return sfq->qs_limit; + else + return -NLE_NOATTR; +} + +/** + * Set perturbation interval of SFQ qdisc. + * @arg qdisc SFQ qdisc to be modified. + * @arg perturb New perturbation interval in seconds. + * @note A value of 0 disables perturbation altogether. + * @return 0 on success or a negative error code. + */ +void rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb) +{ + struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + sfq->qs_perturb = perturb; + sfq->qs_mask |= SCH_SFQ_ATTR_PERTURB; +} + +/** + * Get perturbation interval of SFQ qdisc. + * @arg qdisc SFQ qdisc. + * @return Perturbation interval in seconds or a negative error code. + */ +int rtnl_sfq_get_perturb(struct rtnl_qdisc *qdisc) +{ + struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (sfq->qs_mask & SCH_SFQ_ATTR_PERTURB) + return sfq->qs_perturb; + else + return -NLE_NOATTR; +} + +/** + * Get divisor of SFQ qdisc. + * @arg qdisc SFQ qdisc. + * @return Divisor in number of entries or a negative error code. + */ +int rtnl_sfq_get_divisor(struct rtnl_qdisc *qdisc) +{ + struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (sfq->qs_mask & SCH_SFQ_ATTR_DIVISOR) + return sfq->qs_divisor; + else + return -NLE_NOATTR; +} + +/** @} */ + +static struct rtnl_tc_ops sfq_ops = { + .to_kind = "sfq", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_sfq), + .to_msg_parser = sfq_msg_parser, + .to_dump = { + [NL_DUMP_LINE] = sfq_dump_line, + [NL_DUMP_DETAILS] = sfq_dump_details, + }, + .to_msg_fill = sfq_msg_fill, +}; + +static void __init sfq_init(void) +{ + rtnl_tc_register(&sfq_ops); +} + +static void __exit sfq_exit(void) +{ + rtnl_tc_unregister(&sfq_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/qdisc/tbf.c b/libnetwork/libnl3/lib/route/qdisc/tbf.c new file mode 100644 index 0000000..8a6c400 --- /dev/null +++ b/libnetwork/libnl3/lib/route/qdisc/tbf.c @@ -0,0 +1,460 @@ +/* + * lib/route/qdisc/tbf.c TBF Qdisc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +/** + * @ingroup qdisc + * @defgroup qdisc_tbf Token Bucket Filter (TBF) + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define TBF_ATTR_LIMIT 0x01 +#define TBF_ATTR_RATE 0x02 +#define TBF_ATTR_PEAKRATE 0x10 +/** @endcond */ + +static struct nla_policy tbf_policy[TCA_TBF_MAX+1] = { + [TCA_TBF_PARMS] = { .minlen = sizeof(struct tc_tbf_qopt) }, +}; + +static int tbf_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct nlattr *tb[TCA_TBF_MAX + 1]; + struct rtnl_tbf *tbf = data; + int err; + + if ((err = tca_parse(tb, TCA_TBF_MAX, tc, tbf_policy)) < 0) + return err; + + if (tb[TCA_TBF_PARMS]) { + struct tc_tbf_qopt opts; + int bufsize; + + nla_memcpy(&opts, tb[TCA_TBF_PARMS], sizeof(opts)); + tbf->qt_limit = opts.limit; + + rtnl_copy_ratespec(&tbf->qt_rate, &opts.rate); + tbf->qt_rate_txtime = opts.buffer; + bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer), + opts.rate.rate); + tbf->qt_rate_bucket = bufsize; + + rtnl_copy_ratespec(&tbf->qt_peakrate, &opts.peakrate); + tbf->qt_peakrate_txtime = opts.mtu; + bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.mtu), + opts.peakrate.rate); + tbf->qt_peakrate_bucket = bufsize; + + rtnl_tc_set_mpu(tc, tbf->qt_rate.rs_mpu); + rtnl_tc_set_overhead(tc, tbf->qt_rate.rs_overhead); + + tbf->qt_mask = (TBF_ATTR_LIMIT | TBF_ATTR_RATE | TBF_ATTR_PEAKRATE); + } + + return 0; +} + +static void tbf_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + double r, rbit, lim; + char *ru, *rubit, *limu; + struct rtnl_tbf *tbf = data; + + if (!tbf) + return; + + r = nl_cancel_down_bytes(tbf->qt_rate.rs_rate, &ru); + rbit = nl_cancel_down_bits(tbf->qt_rate.rs_rate*8, &rubit); + lim = nl_cancel_down_bytes(tbf->qt_limit, &limu); + + nl_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s", + r, ru, rbit, rubit, lim, limu); +} + +static void tbf_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_tbf *tbf = data; + + if (!tbf) + return; + + if (1) { + char *bu, *cu; + double bs = nl_cancel_down_bytes(tbf->qt_rate_bucket, &bu); + double cl = nl_cancel_down_bytes(1 << tbf->qt_rate.rs_cell_log, + &cu); + + nl_dump(p, "rate-bucket-size %1.f%s " + "rate-cell-size %.1f%s\n", + bs, bu, cl, cu); + + } + + if (tbf->qt_mask & TBF_ATTR_PEAKRATE) { + char *pru, *prbu, *bsu, *clu; + double pr, prb, bs, cl; + + pr = nl_cancel_down_bytes(tbf->qt_peakrate.rs_rate, &pru); + prb = nl_cancel_down_bits(tbf->qt_peakrate.rs_rate * 8, &prbu); + bs = nl_cancel_down_bits(tbf->qt_peakrate_bucket, &bsu); + cl = nl_cancel_down_bits(1 << tbf->qt_peakrate.rs_cell_log, + &clu); + + nl_dump_line(p, " peak-rate %.2f%s/s (%.0f%s) " + "bucket-size %.1f%s cell-size %.1f%s" + "latency %.1f%s", + pr, pru, prb, prbu, bs, bsu, cl, clu); + } +} + +static int tbf_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) +{ + uint32_t rtab[RTNL_TC_RTABLE_SIZE], ptab[RTNL_TC_RTABLE_SIZE]; + struct tc_tbf_qopt opts; + struct rtnl_tbf *tbf = data; + int required = TBF_ATTR_RATE | TBF_ATTR_LIMIT; + + if (!(tbf->qt_mask & required) != required) + return -NLE_MISSING_ATTR; + + memset(&opts, 0, sizeof(opts)); + opts.limit = tbf->qt_limit; + opts.buffer = tbf->qt_rate_txtime; + + rtnl_tc_build_rate_table(tc, &tbf->qt_rate, rtab); + rtnl_rcopy_ratespec(&opts.rate, &tbf->qt_rate); + + if (tbf->qt_mask & TBF_ATTR_PEAKRATE) { + opts.mtu = tbf->qt_peakrate_txtime; + rtnl_tc_build_rate_table(tc, &tbf->qt_peakrate, ptab); + rtnl_rcopy_ratespec(&opts.peakrate, &tbf->qt_peakrate); + + } + + NLA_PUT(msg, TCA_TBF_PARMS, sizeof(opts), &opts); + NLA_PUT(msg, TCA_TBF_RTAB, sizeof(rtab), rtab); + + if (tbf->qt_mask & TBF_ATTR_PEAKRATE) + NLA_PUT(msg, TCA_TBF_PTAB, sizeof(ptab), ptab); + + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +/** + * @name Attribute Access + * @{ + */ + +/** + * Set limit of TBF qdisc. + * @arg qdisc TBF qdisc to be modified. + * @arg limit New limit in bytes. + * @return 0 on success or a negative error code. + */ +void rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit) +{ + struct rtnl_tbf *tbf; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + tbf->qt_limit = limit; + tbf->qt_mask |= TBF_ATTR_LIMIT; +} + +static inline double calc_limit(struct rtnl_ratespec *spec, int latency, + int bucket) +{ + double limit; + + limit = (double) spec->rs_rate * ((double) latency / 1000000.); + limit += bucket; + + return limit; +} + +/** + * Set limit of TBF qdisc by latency. + * @arg qdisc TBF qdisc to be modified. + * @arg latency Latency in micro seconds. + * + * Calculates and sets the limit based on the desired latency and the + * configured rate and peak rate. In order for this operation to succeed, + * the rate and if required the peak rate must have been set in advance. + * + * @f[ + * limit_n = \frac{{rate_n} \times {latency}}{10^6}+{bucketsize}_n + * @f] + * @f[ + * limit = min(limit_{rate},limit_{peak}) + * @f] + * + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency) +{ + struct rtnl_tbf *tbf; + double limit, limit2; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (!(tbf->qt_mask & TBF_ATTR_RATE)) + return -NLE_MISSING_ATTR; + + limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket); + + if (tbf->qt_mask & TBF_ATTR_PEAKRATE) { + limit2 = calc_limit(&tbf->qt_peakrate, latency, + tbf->qt_peakrate_bucket); + + if (limit2 < limit) + limit = limit2; + } + + rtnl_qdisc_tbf_set_limit(qdisc, (int) limit); + + return 0; +} + +/** + * Get limit of TBF qdisc. + * @arg qdisc TBF qdisc. + * @return Limit in bytes or a negative error code. + */ +int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc) +{ + struct rtnl_tbf *tbf; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_LIMIT) + return tbf->qt_limit; + else + return -NLE_NOATTR; +} + +static inline int calc_cell_log(int cell, int bucket) +{ + cell = rtnl_tc_calc_cell_log(cell); + return cell; +} + +/** + * Set rate of TBF qdisc. + * @arg qdisc TBF qdisc to be modified. + * @arg rate New rate in bytes per second. + * @arg bucket Size of bucket in bytes. + * @arg cell Size of a rate cell or 0 to get default value. + * @return 0 on success or a negative error code. + */ +void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket, + int cell) +{ + struct rtnl_tbf *tbf; + int cell_log; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (!cell) + cell_log = UINT8_MAX; + else + cell_log = rtnl_tc_calc_cell_log(cell); + + tbf->qt_rate.rs_rate = rate; + tbf->qt_rate_bucket = bucket; + tbf->qt_rate.rs_cell_log = cell_log; + tbf->qt_rate_txtime = rtnl_tc_calc_txtime(bucket, rate); + tbf->qt_mask |= TBF_ATTR_RATE; +} + +/** + * Get rate of TBF qdisc. + * @arg qdisc TBF qdisc. + * @return Rate in bytes per seconds or a negative error code. + */ +int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc) +{ + struct rtnl_tbf *tbf; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_RATE) + return tbf->qt_rate.rs_rate; + else + return -1; +} + +/** + * Get rate bucket size of TBF qdisc. + * @arg qdisc TBF qdisc. + * @return Size of rate bucket or a negative error code. + */ +int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *qdisc) +{ + struct rtnl_tbf *tbf; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_RATE) + return tbf->qt_rate_bucket; + else + return -1; +} + +/** + * Get rate cell size of TBF qdisc. + * @arg qdisc TBF qdisc. + * @return Size of rate cell in bytes or a negative error code. + */ +int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *qdisc) +{ + struct rtnl_tbf *tbf; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_RATE) + return (1 << tbf->qt_rate.rs_cell_log); + else + return -1; +} + +/** + * Set peak rate of TBF qdisc. + * @arg qdisc TBF qdisc to be modified. + * @arg rate New peak rate in bytes per second. + * @arg bucket Size of peakrate bucket. + * @arg cell Size of a peakrate cell or 0 to get default value. + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket, + int cell) +{ + struct rtnl_tbf *tbf; + int cell_log; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + cell_log = calc_cell_log(cell, bucket); + if (cell_log < 0) + return cell_log; + + tbf->qt_peakrate.rs_rate = rate; + tbf->qt_peakrate_bucket = bucket; + tbf->qt_peakrate.rs_cell_log = cell_log; + tbf->qt_peakrate_txtime = rtnl_tc_calc_txtime(bucket, rate); + + tbf->qt_mask |= TBF_ATTR_PEAKRATE; + + return 0; +} + +/** + * Get peak rate of TBF qdisc. + * @arg qdisc TBF qdisc. + * @return Peak rate in bytes per seconds or a negative error code. + */ +int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc) +{ + struct rtnl_tbf *tbf; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_PEAKRATE) + return tbf->qt_peakrate.rs_rate; + else + return -1; +} + +/** + * Get peak rate bucket size of TBF qdisc. + * @arg qdisc TBF qdisc. + * @return Size of peak rate bucket or a negative error code. + */ +int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *qdisc) +{ + struct rtnl_tbf *tbf; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_PEAKRATE) + return tbf->qt_peakrate_bucket; + else + return -1; +} + +/** + * Get peak rate cell size of TBF qdisc. + * @arg qdisc TBF qdisc. + * @return Size of peak rate cell in bytes or a negative error code. + */ +int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc) +{ + struct rtnl_tbf *tbf; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_PEAKRATE) + return (1 << tbf->qt_peakrate.rs_cell_log); + else + return -1; +} + +/** @} */ + +static struct rtnl_tc_ops tbf_tc_ops = { + .to_kind = "tbf", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_tbf), + .to_msg_parser = tbf_msg_parser, + .to_dump = { + [NL_DUMP_LINE] = tbf_dump_line, + [NL_DUMP_DETAILS] = tbf_dump_details, + }, + .to_msg_fill = tbf_msg_fill, +}; + +static void __init tbf_init(void) +{ + rtnl_tc_register(&tbf_tc_ops); +} + +static void __exit tbf_exit(void) +{ + rtnl_tc_unregister(&tbf_tc_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/route.c b/libnetwork/libnl3/lib/route/route.c new file mode 100644 index 0000000..f684f96 --- /dev/null +++ b/libnetwork/libnl3/lib/route/route.c @@ -0,0 +1,202 @@ +/* + * lib/route/route.c Routes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup rtnl + * @defgroup route Routing + * @brief + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct nl_cache_ops rtnl_route_ops; + +static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *nlh, struct nl_parser_param *pp) +{ + struct rtnl_route *route; + int err; + + if ((err = rtnl_route_parse(nlh, &route)) < 0) + return err; + + err = pp->pp_cb((struct nl_object *) route, pp); + + rtnl_route_put(route); + return err; +} + +static int route_request_update(struct nl_cache *c, struct nl_sock *h) +{ + struct rtmsg rhdr = { + .rtm_family = c->c_iarg1, + }; + + if (c->c_iarg2 & ROUTE_CACHE_CONTENT) + rhdr.rtm_flags |= RTM_F_CLONED; + + return nl_send_simple(h, RTM_GETROUTE, NLM_F_DUMP, &rhdr, sizeof(rhdr)); +} + +/** + * @name Cache Management + * @{ + */ + +/** + * Build a route cache holding all routes currently configured in the kernel + * @arg sk Netlink socket. + * @arg family Address family of routes to cover or AF_UNSPEC + * @arg flags Flags + * @arg result Result pointer + * + * Allocates a new cache, initializes it properly and updates it to + * contain all routes currently configured in the kernel. + * + * @note The caller is responsible for destroying and freeing the + * cache after using it. + * @return 0 on success or a negative error code. + */ +int rtnl_route_alloc_cache(struct nl_sock *sk, int family, int flags, + struct nl_cache **result) +{ + struct nl_cache *cache; + int err; + + if (!(cache = nl_cache_alloc(&rtnl_route_ops))) + return -NLE_NOMEM; + + cache->c_iarg1 = family; + cache->c_iarg2 = flags; + + if (sk && (err = nl_cache_refill(sk, cache)) < 0) { + free(cache); + return err; + } + + *result = cache; + return 0; +} + +/** @} */ + +/** + * @name Route Addition + * @{ + */ + +static int build_route_msg(struct rtnl_route *tmpl, int cmd, int flags, + struct nl_msg **result) +{ + struct nl_msg *msg; + int err; + + if (!(msg = nlmsg_alloc_simple(cmd, flags))) + return -NLE_NOMEM; + + if ((err = rtnl_route_build_msg(msg, tmpl)) < 0) { + nlmsg_free(msg); + return err; + } + + *result = msg; + return 0; +} + +int rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags, + struct nl_msg **result) +{ + return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags, + result); +} + +int rtnl_route_add(struct nl_sock *sk, struct rtnl_route *route, int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_route_build_add_request(route, flags, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +int rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags, + struct nl_msg **result) +{ + return build_route_msg(tmpl, RTM_DELROUTE, flags, result); +} + +int rtnl_route_delete(struct nl_sock *sk, struct rtnl_route *route, int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_route_build_del_request(route, flags, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +/** @} */ + +static struct nl_af_group route_groups[] = { + { AF_INET, RTNLGRP_IPV4_ROUTE }, + { AF_INET6, RTNLGRP_IPV6_ROUTE }, + { AF_DECnet, RTNLGRP_DECnet_ROUTE }, + { END_OF_GROUP_LIST }, +}; + +static struct nl_cache_ops rtnl_route_ops = { + .co_name = "route/route", + .co_hdrsize = sizeof(struct rtmsg), + .co_msgtypes = { + { RTM_NEWROUTE, NL_ACT_NEW, "new" }, + { RTM_DELROUTE, NL_ACT_DEL, "del" }, + { RTM_GETROUTE, NL_ACT_GET, "get" }, + END_OF_MSGTYPES_LIST, + }, + .co_protocol = NETLINK_ROUTE, + .co_groups = route_groups, + .co_request_update = route_request_update, + .co_msg_parser = route_msg_parser, + .co_obj_ops = &route_obj_ops, +}; + +static void __init route_init(void) +{ + nl_cache_mngt_register(&rtnl_route_ops); +} + +static void __exit route_exit(void) +{ + nl_cache_mngt_unregister(&rtnl_route_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/route_obj.c b/libnetwork/libnl3/lib/route/route_obj.c new file mode 100644 index 0000000..d322633 --- /dev/null +++ b/libnetwork/libnl3/lib/route/route_obj.c @@ -0,0 +1,1148 @@ +/* + * lib/route/route_obj.c Route Object + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup route + * @defgroup route_obj Route Object + * + * @par Attributes + * @code + * Name Default + * ------------------------------------------------------------- + * routing table RT_TABLE_MAIN + * scope RT_SCOPE_NOWHERE + * tos 0 + * protocol RTPROT_STATIC + * prio 0 + * family AF_UNSPEC + * type RTN_UNICAST + * iif NULL + * @endcode + * + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define ROUTE_ATTR_FAMILY 0x000001 +#define ROUTE_ATTR_TOS 0x000002 +#define ROUTE_ATTR_TABLE 0x000004 +#define ROUTE_ATTR_PROTOCOL 0x000008 +#define ROUTE_ATTR_SCOPE 0x000010 +#define ROUTE_ATTR_TYPE 0x000020 +#define ROUTE_ATTR_FLAGS 0x000040 +#define ROUTE_ATTR_DST 0x000080 +#define ROUTE_ATTR_SRC 0x000100 +#define ROUTE_ATTR_IIF 0x000200 +#define ROUTE_ATTR_OIF 0x000400 +#define ROUTE_ATTR_GATEWAY 0x000800 +#define ROUTE_ATTR_PRIO 0x001000 +#define ROUTE_ATTR_PREF_SRC 0x002000 +#define ROUTE_ATTR_METRICS 0x004000 +#define ROUTE_ATTR_MULTIPATH 0x008000 +#define ROUTE_ATTR_REALMS 0x010000 +#define ROUTE_ATTR_CACHEINFO 0x020000 +/** @endcond */ + +static void route_constructor(struct nl_object *c) +{ + struct rtnl_route *r = (struct rtnl_route *) c; + + r->rt_family = AF_UNSPEC; + r->rt_scope = RT_SCOPE_NOWHERE; + r->rt_table = RT_TABLE_MAIN; + r->rt_protocol = RTPROT_STATIC; + r->rt_type = RTN_UNICAST; + + nl_init_list_head(&r->rt_nexthops); +} + +static void route_free_data(struct nl_object *c) +{ + struct rtnl_route *r = (struct rtnl_route *) c; + struct rtnl_nexthop *nh, *tmp; + + if (r == NULL) + return; + + nl_addr_put(r->rt_dst); + nl_addr_put(r->rt_src); + nl_addr_put(r->rt_pref_src); + + nl_list_for_each_entry_safe(nh, tmp, &r->rt_nexthops, rtnh_list) { + rtnl_route_remove_nexthop(r, nh); + rtnl_route_nh_free(nh); + } +} + +static int route_clone(struct nl_object *_dst, struct nl_object *_src) +{ + struct rtnl_route *dst = (struct rtnl_route *) _dst; + struct rtnl_route *src = (struct rtnl_route *) _src; + struct rtnl_nexthop *nh, *new; + + if (src->rt_dst) + if (!(dst->rt_dst = nl_addr_clone(src->rt_dst))) + return -NLE_NOMEM; + + if (src->rt_src) + if (!(dst->rt_src = nl_addr_clone(src->rt_src))) + return -NLE_NOMEM; + + if (src->rt_pref_src) + if (!(dst->rt_pref_src = nl_addr_clone(src->rt_pref_src))) + return -NLE_NOMEM; + + nl_init_list_head(&dst->rt_nexthops); + nl_list_for_each_entry(nh, &src->rt_nexthops, rtnh_list) { + new = rtnl_route_nh_clone(nh); + if (!new) + return -NLE_NOMEM; + + rtnl_route_add_nexthop(dst, new); + } + + return 0; +} + +static void route_dump_line(struct nl_object *a, struct nl_dump_params *p) +{ + struct rtnl_route *r = (struct rtnl_route *) a; + int cache = 0, flags; + char buf[64]; + + if (r->rt_flags & RTM_F_CLONED) + cache = 1; + + nl_dump_line(p, "%s ", nl_af2str(r->rt_family, buf, sizeof(buf))); + + if (cache) + nl_dump(p, "cache "); + + if (!(r->ce_mask & ROUTE_ATTR_DST) || + nl_addr_get_len(r->rt_dst) == 0) + nl_dump(p, "default "); + else + nl_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf))); + + if (r->ce_mask & ROUTE_ATTR_TABLE && !cache) + nl_dump(p, "table %s ", + rtnl_route_table2str(r->rt_table, buf, sizeof(buf))); + + if (r->ce_mask & ROUTE_ATTR_TYPE) + nl_dump(p, "type %s ", + nl_rtntype2str(r->rt_type, buf, sizeof(buf))); + + if (r->ce_mask & ROUTE_ATTR_TOS && r->rt_tos != 0) + nl_dump(p, "tos %#x ", r->rt_tos); + + if (r->ce_mask & ROUTE_ATTR_MULTIPATH) { + struct rtnl_nexthop *nh; + + nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) { + p->dp_ivar = NH_DUMP_FROM_ONELINE; + rtnl_route_nh_dump(nh, p); + } + } + + flags = r->rt_flags & ~(RTM_F_CLONED); + if (r->ce_mask & ROUTE_ATTR_FLAGS && flags) { + + nl_dump(p, "<"); + +#define PRINT_FLAG(f) if (flags & RTNH_F_##f) { \ + flags &= ~RTNH_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); } + PRINT_FLAG(DEAD); + PRINT_FLAG(ONLINK); + PRINT_FLAG(PERVASIVE); +#undef PRINT_FLAG + +#define PRINT_FLAG(f) if (flags & RTM_F_##f) { \ + flags &= ~RTM_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); } + PRINT_FLAG(NOTIFY); + PRINT_FLAG(EQUALIZE); + PRINT_FLAG(PREFIX); +#undef PRINT_FLAG + +#define PRINT_FLAG(f) if (flags & RTCF_##f) { \ + flags &= ~RTCF_##f; nl_dump(p, #f "%s", flags ? "," : ""); } + PRINT_FLAG(NOTIFY); + PRINT_FLAG(REDIRECTED); + PRINT_FLAG(DOREDIRECT); + PRINT_FLAG(DIRECTSRC); + PRINT_FLAG(DNAT); + PRINT_FLAG(BROADCAST); + PRINT_FLAG(MULTICAST); + PRINT_FLAG(LOCAL); +#undef PRINT_FLAG + + nl_dump(p, ">"); + } + + nl_dump(p, "\n"); +} + +static void route_dump_details(struct nl_object *a, struct nl_dump_params *p) +{ + struct rtnl_route *r = (struct rtnl_route *) a; + struct nl_cache *link_cache; + char buf[128]; + int i; + + link_cache = nl_cache_mngt_require("route/link"); + + route_dump_line(a, p); + nl_dump_line(p, " "); + + if (r->ce_mask & ROUTE_ATTR_PREF_SRC) + nl_dump(p, "preferred-src %s ", + nl_addr2str(r->rt_pref_src, buf, sizeof(buf))); + + if (r->ce_mask & ROUTE_ATTR_SCOPE && r->rt_scope != RT_SCOPE_NOWHERE) + nl_dump(p, "scope %s ", + rtnl_scope2str(r->rt_scope, buf, sizeof(buf))); + + if (r->ce_mask & ROUTE_ATTR_PRIO) + nl_dump(p, "priority %#x ", r->rt_prio); + + if (r->ce_mask & ROUTE_ATTR_PROTOCOL) + nl_dump(p, "protocol %s ", + rtnl_route_proto2str(r->rt_protocol, buf, sizeof(buf))); + + if (r->ce_mask & ROUTE_ATTR_IIF) { + if (link_cache) { + nl_dump(p, "iif %s ", + rtnl_link_i2name(link_cache, r->rt_iif, + buf, sizeof(buf))); + } else + nl_dump(p, "iif %d ", r->rt_iif); + } + + if (r->ce_mask & ROUTE_ATTR_SRC) + nl_dump(p, "src %s ", nl_addr2str(r->rt_src, buf, sizeof(buf))); + + nl_dump(p, "\n"); + + if (r->ce_mask & ROUTE_ATTR_MULTIPATH) { + struct rtnl_nexthop *nh; + + nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) { + nl_dump_line(p, " "); + p->dp_ivar = NH_DUMP_FROM_DETAILS; + rtnl_route_nh_dump(nh, p); + nl_dump(p, "\n"); + } + } + + if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) && r->rt_cacheinfo.rtci_error) { + nl_dump_line(p, " cacheinfo error %d (%s)\n", + r->rt_cacheinfo.rtci_error, + strerror(-r->rt_cacheinfo.rtci_error)); + } + + if (r->ce_mask & ROUTE_ATTR_METRICS) { + nl_dump_line(p, " metrics ["); + for (i = 0; i < RTAX_MAX; i++) + if (r->rt_metrics_mask & (1 << i)) + nl_dump(p, "%s %u ", + rtnl_route_metric2str(i+1, + buf, sizeof(buf)), + r->rt_metrics[i]); + nl_dump(p, "]\n"); + } +} + +static void route_dump_stats(struct nl_object *obj, struct nl_dump_params *p) +{ + struct rtnl_route *route = (struct rtnl_route *) obj; + + route_dump_details(obj, p); + + if (route->ce_mask & ROUTE_ATTR_CACHEINFO) { + struct rtnl_rtcacheinfo *ci = &route->rt_cacheinfo; + + nl_dump_line(p, " used %u refcnt %u last-use %us " + "expires %us\n", + ci->rtci_used, ci->rtci_clntref, + ci->rtci_last_use / nl_get_user_hz(), + ci->rtci_expires / nl_get_user_hz()); + } +} + +static int route_compare(struct nl_object *_a, struct nl_object *_b, + uint32_t attrs, int flags) +{ + struct rtnl_route *a = (struct rtnl_route *) _a; + struct rtnl_route *b = (struct rtnl_route *) _b; + struct rtnl_nexthop *nh_a, *nh_b; + int i, diff = 0, found; + +#define ROUTE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ROUTE_ATTR_##ATTR, a, b, EXPR) + + diff |= ROUTE_DIFF(FAMILY, a->rt_family != b->rt_family); + diff |= ROUTE_DIFF(TOS, a->rt_tos != b->rt_tos); + diff |= ROUTE_DIFF(TABLE, a->rt_table != b->rt_table); + diff |= ROUTE_DIFF(PROTOCOL, a->rt_protocol != b->rt_protocol); + diff |= ROUTE_DIFF(SCOPE, a->rt_scope != b->rt_scope); + diff |= ROUTE_DIFF(TYPE, a->rt_type != b->rt_type); + diff |= ROUTE_DIFF(PRIO, a->rt_prio != b->rt_prio); + diff |= ROUTE_DIFF(DST, nl_addr_cmp(a->rt_dst, b->rt_dst)); + diff |= ROUTE_DIFF(SRC, nl_addr_cmp(a->rt_src, b->rt_src)); + diff |= ROUTE_DIFF(IIF, a->rt_iif != b->rt_iif); + diff |= ROUTE_DIFF(PREF_SRC, nl_addr_cmp(a->rt_pref_src, + b->rt_pref_src)); + + if (flags & LOOSE_COMPARISON) { + nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) { + found = 0; + nl_list_for_each_entry(nh_a, &a->rt_nexthops, + rtnh_list) { + if (!rtnl_route_nh_compare(nh_a, nh_b, + nh_b->ce_mask, 1)) { + found = 1; + break; + } + } + + if (!found) + goto nh_mismatch; + } + + for (i = 0; i < RTAX_MAX - 1; i++) { + if (a->rt_metrics_mask & (1 << i) && + (!(b->rt_metrics_mask & (1 << i)) || + a->rt_metrics[i] != b->rt_metrics[i])) + ROUTE_DIFF(METRICS, 1); + } + + diff |= ROUTE_DIFF(FLAGS, + (a->rt_flags ^ b->rt_flags) & b->rt_flag_mask); + } else { + if (a->rt_nr_nh != a->rt_nr_nh) + goto nh_mismatch; + + /* search for a dup in each nh of a */ + nl_list_for_each_entry(nh_a, &a->rt_nexthops, rtnh_list) { + found = 0; + nl_list_for_each_entry(nh_b, &b->rt_nexthops, + rtnh_list) { + if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0)) { + found = 1; + break; + } + } + if (!found) + goto nh_mismatch; + } + + /* search for a dup in each nh of b, covers case where a has + * dupes itself */ + nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) { + found = 0; + nl_list_for_each_entry(nh_a, &a->rt_nexthops, + rtnh_list) { + if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0)) { + found = 1; + break; + } + } + if (!found) + goto nh_mismatch; + } + + for (i = 0; i < RTAX_MAX - 1; i++) { + if ((a->rt_metrics_mask & (1 << i)) ^ + (b->rt_metrics_mask & (1 << i))) + diff |= ROUTE_DIFF(METRICS, 1); + else + diff |= ROUTE_DIFF(METRICS, + a->rt_metrics[i] != b->rt_metrics[i]); + } + + diff |= ROUTE_DIFF(FLAGS, a->rt_flags != b->rt_flags); + } + +out: + return diff; + +nh_mismatch: + diff |= ROUTE_DIFF(MULTIPATH, 1); + goto out; + +#undef ROUTE_DIFF +} + +static const struct trans_tbl route_attrs[] = { + __ADD(ROUTE_ATTR_FAMILY, family) + __ADD(ROUTE_ATTR_TOS, tos) + __ADD(ROUTE_ATTR_TABLE, table) + __ADD(ROUTE_ATTR_PROTOCOL, protocol) + __ADD(ROUTE_ATTR_SCOPE, scope) + __ADD(ROUTE_ATTR_TYPE, type) + __ADD(ROUTE_ATTR_FLAGS, flags) + __ADD(ROUTE_ATTR_DST, dst) + __ADD(ROUTE_ATTR_SRC, src) + __ADD(ROUTE_ATTR_IIF, iif) + __ADD(ROUTE_ATTR_OIF, oif) + __ADD(ROUTE_ATTR_GATEWAY, gateway) + __ADD(ROUTE_ATTR_PRIO, prio) + __ADD(ROUTE_ATTR_PREF_SRC, pref_src) + __ADD(ROUTE_ATTR_METRICS, metrics) + __ADD(ROUTE_ATTR_MULTIPATH, multipath) + __ADD(ROUTE_ATTR_REALMS, realms) + __ADD(ROUTE_ATTR_CACHEINFO, cacheinfo) +}; + +static char *route_attrs2str(int attrs, char *buf, size_t len) +{ + return __flags2str(attrs, buf, len, route_attrs, + ARRAY_SIZE(route_attrs)); +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct rtnl_route *rtnl_route_alloc(void) +{ + return (struct rtnl_route *) nl_object_alloc(&route_obj_ops); +} + +void rtnl_route_get(struct rtnl_route *route) +{ + nl_object_get((struct nl_object *) route); +} + +void rtnl_route_put(struct rtnl_route *route) +{ + nl_object_put((struct nl_object *) route); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void rtnl_route_set_table(struct rtnl_route *route, uint32_t table) +{ + route->rt_table = table; + route->ce_mask |= ROUTE_ATTR_TABLE; +} + +uint32_t rtnl_route_get_table(struct rtnl_route *route) +{ + return route->rt_table; +} + +void rtnl_route_set_scope(struct rtnl_route *route, uint8_t scope) +{ + route->rt_scope = scope; + route->ce_mask |= ROUTE_ATTR_SCOPE; +} + +uint8_t rtnl_route_get_scope(struct rtnl_route *route) +{ + return route->rt_scope; +} + +void rtnl_route_set_tos(struct rtnl_route *route, uint8_t tos) +{ + route->rt_tos = tos; + route->ce_mask |= ROUTE_ATTR_TOS; +} + +uint8_t rtnl_route_get_tos(struct rtnl_route *route) +{ + return route->rt_tos; +} + +void rtnl_route_set_protocol(struct rtnl_route *route, uint8_t protocol) +{ + route->rt_protocol = protocol; + route->ce_mask |= ROUTE_ATTR_PROTOCOL; +} + +uint8_t rtnl_route_get_protocol(struct rtnl_route *route) +{ + return route->rt_protocol; +} + +void rtnl_route_set_priority(struct rtnl_route *route, uint32_t prio) +{ + route->rt_prio = prio; + route->ce_mask |= ROUTE_ATTR_PRIO; +} + +uint32_t rtnl_route_get_priority(struct rtnl_route *route) +{ + return route->rt_prio; +} + +int rtnl_route_set_family(struct rtnl_route *route, uint8_t family) +{ + if (family != AF_INET && family != AF_INET6 && family != AF_DECnet) + return -NLE_AF_NOSUPPORT; + + route->rt_family = family; + route->ce_mask |= ROUTE_ATTR_FAMILY; + + return 0; +} + +uint8_t rtnl_route_get_family(struct rtnl_route *route) +{ + return route->rt_family; +} + +int rtnl_route_set_dst(struct rtnl_route *route, struct nl_addr *addr) +{ + if (route->ce_mask & ROUTE_ATTR_FAMILY) { + if (addr->a_family != route->rt_family) + return -NLE_AF_MISMATCH; + } else + route->rt_family = addr->a_family; + + if (route->rt_dst) + nl_addr_put(route->rt_dst); + + nl_addr_get(addr); + route->rt_dst = addr; + + route->ce_mask |= (ROUTE_ATTR_DST | ROUTE_ATTR_FAMILY); + + return 0; +} + +struct nl_addr *rtnl_route_get_dst(struct rtnl_route *route) +{ + return route->rt_dst; +} + +int rtnl_route_set_src(struct rtnl_route *route, struct nl_addr *addr) +{ + if (addr->a_family == AF_INET) + return -NLE_SRCRT_NOSUPPORT; + + if (route->ce_mask & ROUTE_ATTR_FAMILY) { + if (addr->a_family != route->rt_family) + return -NLE_AF_MISMATCH; + } else + route->rt_family = addr->a_family; + + if (route->rt_src) + nl_addr_put(route->rt_src); + + nl_addr_get(addr); + route->rt_src = addr; + route->ce_mask |= (ROUTE_ATTR_SRC | ROUTE_ATTR_FAMILY); + + return 0; +} + +struct nl_addr *rtnl_route_get_src(struct rtnl_route *route) +{ + return route->rt_src; +} + +int rtnl_route_set_type(struct rtnl_route *route, uint8_t type) +{ + if (type > RTN_MAX) + return -NLE_RANGE; + + route->rt_type = type; + route->ce_mask |= ROUTE_ATTR_TYPE; + + return 0; +} + +uint8_t rtnl_route_get_type(struct rtnl_route *route) +{ + return route->rt_type; +} + +void rtnl_route_set_flags(struct rtnl_route *route, uint32_t flags) +{ + route->rt_flag_mask |= flags; + route->rt_flags |= flags; + route->ce_mask |= ROUTE_ATTR_FLAGS; +} + +void rtnl_route_unset_flags(struct rtnl_route *route, uint32_t flags) +{ + route->rt_flag_mask |= flags; + route->rt_flags &= ~flags; + route->ce_mask |= ROUTE_ATTR_FLAGS; +} + +uint32_t rtnl_route_get_flags(struct rtnl_route *route) +{ + return route->rt_flags; +} + +int rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value) +{ + if (metric > RTAX_MAX || metric < 1) + return -NLE_RANGE; + + route->rt_metrics[metric - 1] = value; + + if (!(route->rt_metrics_mask & (1 << (metric - 1)))) { + route->rt_nmetrics++; + route->rt_metrics_mask |= (1 << (metric - 1)); + } + + route->ce_mask |= ROUTE_ATTR_METRICS; + + return 0; +} + +int rtnl_route_unset_metric(struct rtnl_route *route, int metric) +{ + if (metric > RTAX_MAX || metric < 1) + return -NLE_RANGE; + + if (route->rt_metrics_mask & (1 << (metric - 1))) { + route->rt_nmetrics--; + route->rt_metrics_mask &= ~(1 << (metric - 1)); + } + + return 0; +} + +int rtnl_route_get_metric(struct rtnl_route *route, int metric, uint32_t *value) +{ + if (metric > RTAX_MAX || metric < 1) + return -NLE_RANGE; + + if (!(route->rt_metrics_mask & (1 << (metric - 1)))) + return -NLE_OBJ_NOTFOUND; + + if (value) + *value = route->rt_metrics[metric - 1]; + + return 0; +} + +int rtnl_route_set_pref_src(struct rtnl_route *route, struct nl_addr *addr) +{ + if (route->ce_mask & ROUTE_ATTR_FAMILY) { + if (addr->a_family != route->rt_family) + return -NLE_AF_MISMATCH; + } else + route->rt_family = addr->a_family; + + if (route->rt_pref_src) + nl_addr_put(route->rt_pref_src); + + nl_addr_get(addr); + route->rt_pref_src = addr; + route->ce_mask |= (ROUTE_ATTR_PREF_SRC | ROUTE_ATTR_FAMILY); + + return 0; +} + +struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *route) +{ + return route->rt_pref_src; +} + +void rtnl_route_set_iif(struct rtnl_route *route, int ifindex) +{ + route->rt_iif = ifindex; + route->ce_mask |= ROUTE_ATTR_IIF; +} + +int rtnl_route_get_iif(struct rtnl_route *route) +{ + return route->rt_iif; +} + +void rtnl_route_add_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh) +{ + nl_list_add_tail(&nh->rtnh_list, &route->rt_nexthops); + route->rt_nr_nh++; + route->ce_mask |= ROUTE_ATTR_MULTIPATH; +} + +void rtnl_route_remove_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh) +{ + if (route->ce_mask & ROUTE_ATTR_MULTIPATH) { + route->rt_nr_nh--; + nl_list_del(&nh->rtnh_list); + } +} + +struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *route) +{ + if (route->ce_mask & ROUTE_ATTR_MULTIPATH) + return &route->rt_nexthops; + + return NULL; +} + +int rtnl_route_get_nnexthops(struct rtnl_route *route) +{ + if (route->ce_mask & ROUTE_ATTR_MULTIPATH) + return route->rt_nr_nh; + + return 0; +} + +void rtnl_route_foreach_nexthop(struct rtnl_route *r, + void (*cb)(struct rtnl_nexthop *, void *), + void *arg) +{ + struct rtnl_nexthop *nh; + + if (r->ce_mask & ROUTE_ATTR_MULTIPATH) { + nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) { + cb(nh, arg); + } + } +} + +struct rtnl_nexthop *rtnl_route_nexthop_n(struct rtnl_route *r, int n) +{ + struct rtnl_nexthop *nh; + int i; + + if (r->ce_mask & ROUTE_ATTR_MULTIPATH && r->rt_nr_nh > n) { + i = 0; + nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) { + if (i == n) return nh; + i++; + } + } + return NULL; +} + +/** @} */ + +/** + * @name Utilities + * @{ + */ + +/** + * Guess scope of a route object. + * @arg route Route object. + * + * Guesses the scope of a route object, based on the following rules: + * @code + * 1) Local route -> local scope + * 2) At least one nexthop not directly connected -> universe scope + * 3) All others -> link scope + * @endcode + * + * @return Scope value. + */ +int rtnl_route_guess_scope(struct rtnl_route *route) +{ + if (route->rt_type == RTN_LOCAL) + return RT_SCOPE_HOST; + + if (!nl_list_empty(&route->rt_nexthops)) { + struct rtnl_nexthop *nh; + + /* + * Use scope uiniverse if there is at least one nexthop which + * is not directly connected + */ + nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) { + if (nh->rtnh_gateway) + return RT_SCOPE_UNIVERSE; + } + } + + return RT_SCOPE_LINK; +} + +/** @} */ + +static struct nla_policy route_policy[RTA_MAX+1] = { + [RTA_IIF] = { .type = NLA_U32 }, + [RTA_OIF] = { .type = NLA_U32 }, + [RTA_PRIORITY] = { .type = NLA_U32 }, + [RTA_FLOW] = { .type = NLA_U32 }, + [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) }, + [RTA_METRICS] = { .type = NLA_NESTED }, + [RTA_MULTIPATH] = { .type = NLA_NESTED }, +}; + +static int parse_multipath(struct rtnl_route *route, struct nlattr *attr) +{ + struct rtnl_nexthop *nh = NULL; + struct rtnexthop *rtnh = nla_data(attr); + size_t tlen = nla_len(attr); + int err; + + while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) { + nh = rtnl_route_nh_alloc(); + if (!nh) + return -NLE_NOMEM; + + rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops); + rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex); + rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags); + + if (rtnh->rtnh_len > sizeof(*rtnh)) { + struct nlattr *ntb[RTA_MAX + 1]; + + err = nla_parse(ntb, RTA_MAX, (struct nlattr *) + RTNH_DATA(rtnh), + rtnh->rtnh_len - sizeof(*rtnh), + route_policy); + if (err < 0) + goto errout; + + if (ntb[RTA_GATEWAY]) { + struct nl_addr *addr; + + addr = nl_addr_alloc_attr(ntb[RTA_GATEWAY], + route->rt_family); + if (!addr) { + err = -NLE_NOMEM; + goto errout; + } + + rtnl_route_nh_set_gateway(nh, addr); + nl_addr_put(addr); + } + + if (ntb[RTA_FLOW]) { + uint32_t realms; + + realms = nla_get_u32(ntb[RTA_FLOW]); + rtnl_route_nh_set_realms(nh, realms); + } + } + + rtnl_route_add_nexthop(route, nh); + tlen -= RTNH_ALIGN(rtnh->rtnh_len); + rtnh = RTNH_NEXT(rtnh); + } + + err = 0; +errout: + if (err && nh) + rtnl_route_nh_free(nh); + + return err; +} + +int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result) +{ + struct rtmsg *rtm; + struct rtnl_route *route; + struct nlattr *tb[RTA_MAX + 1]; + struct nl_addr *src = NULL, *dst = NULL, *addr; + struct rtnl_nexthop *old_nh = NULL; + int err, family; + + route = rtnl_route_alloc(); + if (!route) { + err = -NLE_NOMEM; + goto errout; + } + + route->ce_msgtype = nlh->nlmsg_type; + + err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, route_policy); + if (err < 0) + goto errout; + + rtm = nlmsg_data(nlh); + route->rt_family = family = rtm->rtm_family; + route->rt_tos = rtm->rtm_tos; + route->rt_table = rtm->rtm_table; + route->rt_type = rtm->rtm_type; + route->rt_scope = rtm->rtm_scope; + route->rt_protocol = rtm->rtm_protocol; + route->rt_flags = rtm->rtm_flags; + + route->ce_mask |= ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS | + ROUTE_ATTR_TABLE | ROUTE_ATTR_TYPE | + ROUTE_ATTR_SCOPE | ROUTE_ATTR_PROTOCOL | + ROUTE_ATTR_FLAGS; + + if (tb[RTA_DST]) { + if (!(dst = nl_addr_alloc_attr(tb[RTA_DST], family))) + goto errout_nomem; + } else { + if (!(dst = nl_addr_alloc(0))) + goto errout_nomem; + nl_addr_set_family(dst, rtm->rtm_family); + } + + nl_addr_set_prefixlen(dst, rtm->rtm_dst_len); + err = rtnl_route_set_dst(route, dst); + if (err < 0) + goto errout; + + nl_addr_put(dst); + + if (tb[RTA_SRC]) { + if (!(src = nl_addr_alloc_attr(tb[RTA_SRC], family))) + goto errout_nomem; + } else if (rtm->rtm_src_len) + if (!(src = nl_addr_alloc(0))) + goto errout_nomem; + + if (src) { + nl_addr_set_prefixlen(src, rtm->rtm_src_len); + rtnl_route_set_src(route, src); + nl_addr_put(src); + } + + if (tb[RTA_IIF]) + rtnl_route_set_iif(route, nla_get_u32(tb[RTA_IIF])); + + if (tb[RTA_PRIORITY]) + rtnl_route_set_priority(route, nla_get_u32(tb[RTA_PRIORITY])); + + if (tb[RTA_PREFSRC]) { + if (!(addr = nl_addr_alloc_attr(tb[RTA_PREFSRC], family))) + goto errout_nomem; + rtnl_route_set_pref_src(route, addr); + nl_addr_put(addr); + } + + if (tb[RTA_METRICS]) { + struct nlattr *mtb[RTAX_MAX + 1]; + int i; + + err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL); + if (err < 0) + goto errout; + + for (i = 1; i <= RTAX_MAX; i++) { + if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) { + uint32_t m = nla_get_u32(mtb[i]); + if (rtnl_route_set_metric(route, i, m) < 0) + goto errout; + } + } + } + + if (tb[RTA_MULTIPATH]) + if ((err = parse_multipath(route, tb[RTA_MULTIPATH])) < 0) + goto errout; + + if (tb[RTA_CACHEINFO]) { + nla_memcpy(&route->rt_cacheinfo, tb[RTA_CACHEINFO], + sizeof(route->rt_cacheinfo)); + route->ce_mask |= ROUTE_ATTR_CACHEINFO; + } + + if (tb[RTA_OIF]) { + if (!old_nh && !(old_nh = rtnl_route_nh_alloc())) + goto errout; + + rtnl_route_nh_set_ifindex(old_nh, nla_get_u32(tb[RTA_OIF])); + } + + if (tb[RTA_GATEWAY]) { + if (!old_nh && !(old_nh = rtnl_route_nh_alloc())) + goto errout; + + if (!(addr = nl_addr_alloc_attr(tb[RTA_GATEWAY], family))) + goto errout_nomem; + + rtnl_route_nh_set_gateway(old_nh, addr); + nl_addr_put(addr); + } + + if (tb[RTA_FLOW]) { + if (!old_nh && !(old_nh = rtnl_route_nh_alloc())) + goto errout; + + rtnl_route_nh_set_realms(old_nh, nla_get_u32(tb[RTA_FLOW])); + } + + if (old_nh) { + if (route->rt_nr_nh == 0) { + /* If no nexthops have been provided via RTA_MULTIPATH + * we add it as regular nexthop to maintain backwards + * compatibility */ + rtnl_route_add_nexthop(route, old_nh); + } else { + /* Kernel supports new style nexthop configuration, + * verify that it is a duplicate and discard nexthop. */ + struct rtnl_nexthop *first; + + first = nl_list_first_entry(&route->rt_nexthops, + struct rtnl_nexthop, + rtnh_list); + if (!first) + BUG(); + + if (rtnl_route_nh_compare(old_nh, first, + old_nh->ce_mask, 0)) { + err = -NLE_INVAL; + goto errout; + } + + rtnl_route_nh_free(old_nh); + } + } + + *result = route; + return 0; + +errout: + rtnl_route_put(route); + return err; + +errout_nomem: + err = -NLE_NOMEM; + goto errout; +} + +int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route) +{ + int i; + struct nlattr *metrics; + struct rtmsg rtmsg = { + .rtm_family = route->rt_family, + .rtm_tos = route->rt_tos, + .rtm_table = route->rt_table, + .rtm_protocol = route->rt_protocol, + .rtm_scope = route->rt_scope, + .rtm_type = route->rt_type, + .rtm_flags = route->rt_flags, + }; + + if (route->rt_dst == NULL) + return -NLE_MISSING_ATTR; + + rtmsg.rtm_dst_len = nl_addr_get_prefixlen(route->rt_dst); + if (route->rt_src) + rtmsg.rtm_src_len = nl_addr_get_prefixlen(route->rt_src); + + + if (rtmsg.rtm_scope == RT_SCOPE_NOWHERE) + rtmsg.rtm_scope = rtnl_route_guess_scope(route); + + if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + /* Additional table attribute replacing the 8bit in the header, was + * required to allow more than 256 tables. */ + NLA_PUT_U32(msg, RTA_TABLE, route->rt_table); + + if (nl_addr_get_len(route->rt_dst)) + NLA_PUT_ADDR(msg, RTA_DST, route->rt_dst); + NLA_PUT_U32(msg, RTA_PRIORITY, route->rt_prio); + + if (route->ce_mask & ROUTE_ATTR_SRC) + NLA_PUT_ADDR(msg, RTA_SRC, route->rt_src); + + if (route->ce_mask & ROUTE_ATTR_PREF_SRC) + NLA_PUT_ADDR(msg, RTA_PREFSRC, route->rt_pref_src); + + if (route->ce_mask & ROUTE_ATTR_IIF) + NLA_PUT_U32(msg, RTA_IIF, route->rt_iif); + + if (route->rt_nmetrics > 0) { + uint32_t val; + + metrics = nla_nest_start(msg, RTA_METRICS); + if (metrics == NULL) + goto nla_put_failure; + + for (i = 1; i <= RTAX_MAX; i++) { + if (!rtnl_route_get_metric(route, i, &val)) + NLA_PUT_U32(msg, i, val); + } + + nla_nest_end(msg, metrics); + } + + if (rtnl_route_get_nnexthops(route) == 1) { + struct rtnl_nexthop *nh; + + nh = rtnl_route_nexthop_n(route, 0); + if (nh->rtnh_gateway) + NLA_PUT_ADDR(msg, RTA_GATEWAY, nh->rtnh_gateway); + if (nh->rtnh_ifindex) + NLA_PUT_U32(msg, RTA_OIF, nh->rtnh_ifindex); + if (nh->rtnh_realms) + NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms); + } else if (rtnl_route_get_nnexthops(route) > 1) { + struct nlattr *multipath; + struct rtnl_nexthop *nh; + + if (!(multipath = nla_nest_start(msg, RTA_MULTIPATH))) + goto nla_put_failure; + + nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) { + struct rtnexthop *rtnh; + + rtnh = nlmsg_reserve(msg, sizeof(*rtnh), NLMSG_ALIGNTO); + if (!rtnh) + goto nla_put_failure; + + rtnh->rtnh_flags = nh->rtnh_flags; + rtnh->rtnh_hops = nh->rtnh_weight; + rtnh->rtnh_ifindex = nh->rtnh_ifindex; + + if (nh->rtnh_gateway) + NLA_PUT_ADDR(msg, RTA_GATEWAY, + nh->rtnh_gateway); + + if (nh->rtnh_realms) + NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms); + + rtnh->rtnh_len = nlmsg_tail(msg->nm_nlh) - + (void *) rtnh; + } + + nla_nest_end(msg, multipath); + } + + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +/** @cond SKIP */ +struct nl_object_ops route_obj_ops = { + .oo_name = "route/route", + .oo_size = sizeof(struct rtnl_route), + .oo_constructor = route_constructor, + .oo_free_data = route_free_data, + .oo_clone = route_clone, + .oo_dump = { + [NL_DUMP_LINE] = route_dump_line, + [NL_DUMP_DETAILS] = route_dump_details, + [NL_DUMP_STATS] = route_dump_stats, + }, + .oo_compare = route_compare, + .oo_attrs2str = route_attrs2str, + .oo_id_attrs = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS | + ROUTE_ATTR_TABLE | ROUTE_ATTR_DST), +}; +/** @endcond */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/route_utils.c b/libnetwork/libnl3/lib/route/route_utils.c new file mode 100644 index 0000000..8b73f2b --- /dev/null +++ b/libnetwork/libnl3/lib/route/route_utils.c @@ -0,0 +1,171 @@ +/* + * lib/route/route_utils.c Routing Utilities + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +/** + * @ingroup route + * @defgroup route_utils Utilities + * @brief Routing Utility Functions + * + * + * @par 1) Translating Routing Table Names + * @code + * // libnl is only aware of the de facto standard routing table names. + * // Additional name <-> identifier associations have to be read in via + * // a configuration file, f.e. /etc/iproute2/rt_tables + * err = rtnl_route_read_table_names("/etc/iproute2/rt_tables"); + * + * // Translating a table name to its idenfier + * int table = rtnl_route_str2table("main"); + * + * // ... and the other way around. + * char buf[32]; + * printf("Name: %s\n", + * rtnl_route_table2str(table, buf, sizeof(buf))); + * @endcode + * + * + * + * + * @{ + */ + +#include +#include +#include +#include +#include + +/** + * @name Routing Table Identifier Translations + * @{ + */ + +static NL_LIST_HEAD(table_names); + +static int add_routing_table_name(long id, const char *name) +{ + return __trans_list_add(id, name, &table_names); +} + +static void __init init_routing_table_names(void) +{ + add_routing_table_name(RT_TABLE_UNSPEC, "unspec"); + add_routing_table_name(RT_TABLE_COMPAT, "compat"); + add_routing_table_name(RT_TABLE_DEFAULT, "default"); + add_routing_table_name(RT_TABLE_MAIN, "main"); + add_routing_table_name(RT_TABLE_LOCAL, "local"); +}; + +static void __exit release_routing_table_names(void) +{ + __trans_list_clear(&table_names); +} + +int rtnl_route_read_table_names(const char *path) +{ + __trans_list_clear(&table_names); + + return __nl_read_num_str_file(path, &add_routing_table_name); +} + +char *rtnl_route_table2str(int table, char *buf, size_t size) +{ + return __list_type2str(table, buf, size, &table_names); +} + +int rtnl_route_str2table(const char *name) +{ + return __list_str2type(name, &table_names); +} + + +/** @} */ + +/** + * @name Routing Protocol Translations + * @{ + */ + +static NL_LIST_HEAD(proto_names); + +static int add_proto_name(long id, const char *name) +{ + return __trans_list_add(id, name, &proto_names); +} + +static void __init init_proto_names(void) +{ + add_proto_name(RTPROT_UNSPEC, "unspec"); + add_proto_name(RTPROT_REDIRECT, "redirect"); + add_proto_name(RTPROT_KERNEL, "kernel"); + add_proto_name(RTPROT_BOOT, "boot"); + add_proto_name(RTPROT_STATIC, "static"); +}; + +static void __exit release_proto_names(void) +{ + __trans_list_clear(&proto_names); +} + +int rtnl_route_read_protocol_names(const char *path) +{ + __trans_list_clear(&proto_names); + + return __nl_read_num_str_file(path, &add_proto_name); +} + +char *rtnl_route_proto2str(int proto, char *buf, size_t size) +{ + return __list_type2str(proto, buf, size, &proto_names); +} + +int rtnl_route_str2proto(const char *name) +{ + return __list_str2type(name, &proto_names); +} + +/** @} */ + +/** + * @name Routing Metrices Translations + * @{ + */ + +static const struct trans_tbl route_metrices[] = { + __ADD(RTAX_UNSPEC, unspec) + __ADD(RTAX_LOCK, lock) + __ADD(RTAX_MTU, mtu) + __ADD(RTAX_WINDOW, window) + __ADD(RTAX_RTT, rtt) + __ADD(RTAX_RTTVAR, rttvar) + __ADD(RTAX_SSTHRESH, ssthresh) + __ADD(RTAX_CWND, cwnd) + __ADD(RTAX_ADVMSS, advmss) + __ADD(RTAX_REORDERING, reordering) + __ADD(RTAX_HOPLIMIT, hoplimit) + __ADD(RTAX_INITCWND, initcwnd) + __ADD(RTAX_FEATURES, features) +}; + +char *rtnl_route_metric2str(int metric, char *buf, size_t size) +{ + return __type2str(metric, buf, size, route_metrices, + ARRAY_SIZE(route_metrices)); +} + +int rtnl_route_str2metric(const char *name) +{ + return __str2type(name, route_metrices, ARRAY_SIZE(route_metrices)); +} + +/** @} */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/rtnl.c b/libnetwork/libnl3/lib/route/rtnl.c new file mode 100644 index 0000000..e5c0798 --- /dev/null +++ b/libnetwork/libnl3/lib/route/rtnl.c @@ -0,0 +1,124 @@ +/* + * lib/route/rtnl.c Routing Netlink + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @defgroup rtnl Routing Family + * @{ + */ + +#include +#include +#include +#include + +/** + * @name Sending + * @{ + */ + +/** + * Send routing netlink request message + * @arg sk Netlink socket. + * @arg type Netlink message type. + * @arg family Address family. + * @arg flags Additional netlink message flags. + * + * Fills out a routing netlink request message and sends it out + * using nl_send_simple(). + * + * @return 0 on success or a negative error code. + */ +int nl_rtgen_request(struct nl_sock *sk, int type, int family, int flags) +{ + struct rtgenmsg gmsg = { + .rtgen_family = family, + }; + + return nl_send_simple(sk, type, flags, &gmsg, sizeof(gmsg)); +} + +/** @} */ + +/** + * @name Routing Type Translations + * @{ + */ + +static const struct trans_tbl rtntypes[] = { + __ADD(RTN_UNSPEC,unspec) + __ADD(RTN_UNICAST,unicast) + __ADD(RTN_LOCAL,local) + __ADD(RTN_BROADCAST,broadcast) + __ADD(RTN_ANYCAST,anycast) + __ADD(RTN_MULTICAST,multicast) + __ADD(RTN_BLACKHOLE,blackhole) + __ADD(RTN_UNREACHABLE,unreachable) + __ADD(RTN_PROHIBIT,prohibit) + __ADD(RTN_THROW,throw) + __ADD(RTN_NAT,nat) + __ADD(RTN_XRESOLVE,xresolve) +}; + +char *nl_rtntype2str(int type, char *buf, size_t size) +{ + return __type2str(type, buf, size, rtntypes, ARRAY_SIZE(rtntypes)); +} + +int nl_str2rtntype(const char *name) +{ + return __str2type(name, rtntypes, ARRAY_SIZE(rtntypes)); +} + +/** @} */ + +/** + * @name Scope Translations + * @{ + */ + +static const struct trans_tbl scopes[] = { + __ADD(255,nowhere) + __ADD(254,host) + __ADD(253,link) + __ADD(200,site) + __ADD(0,global) +}; + +char *rtnl_scope2str(int scope, char *buf, size_t size) +{ + return __type2str(scope, buf, size, scopes, ARRAY_SIZE(scopes)); +} + +int rtnl_str2scope(const char *name) +{ + return __str2type(name, scopes, ARRAY_SIZE(scopes)); +} + +/** @} */ + +/** + * @name Realms Translations + * @{ + */ + +char * rtnl_realms2str(uint32_t realms, char *buf, size_t len) +{ + int from = RTNL_REALM_FROM(realms); + int to = RTNL_REALM_TO(realms); + + snprintf(buf, len, "%d/%d", from, to); + + return buf; +} + +/** @} */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/rule.c b/libnetwork/libnl3/lib/route/rule.c new file mode 100644 index 0000000..1a695cd --- /dev/null +++ b/libnetwork/libnl3/lib/route/rule.c @@ -0,0 +1,753 @@ +/* + * lib/route/rule.c Routing Rules + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2010 Thomas Graf + */ + +/** + * @ingroup rtnl + * @defgroup rule Routing Rules + * @brief + * @{ + */ + +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define RULE_ATTR_FAMILY 0x0001 +#define RULE_ATTR_TABLE 0x0002 +#define RULE_ATTR_ACTION 0x0004 +#define RULE_ATTR_FLAGS 0x0008 +#define RULE_ATTR_IIFNAME 0x0010 +#define RULE_ATTR_OIFNAME 0x0020 +#define RULE_ATTR_PRIO 0x0040 +#define RULE_ATTR_MARK 0x0080 +#define RULE_ATTR_MASK 0x0100 +#define RULE_ATTR_GOTO 0x0200 +#define RULE_ATTR_SRC 0x0400 +#define RULE_ATTR_DST 0x0800 +#define RULE_ATTR_DSFIELD 0x1000 +#define RULE_ATTR_FLOW 0x2000 + +static struct nl_cache_ops rtnl_rule_ops; +static struct nl_object_ops rule_obj_ops; +/** @endcond */ + +static void rule_free_data(struct nl_object *c) +{ + struct rtnl_rule *rule = nl_object_priv(c); + + if (!rule) + return; + + nl_addr_put(rule->r_src); + nl_addr_put(rule->r_dst); +} + +static int rule_clone(struct nl_object *_dst, struct nl_object *_src) +{ + struct rtnl_rule *dst = nl_object_priv(_dst); + struct rtnl_rule *src = nl_object_priv(_src); + + if (src->r_src) + if (!(dst->r_src = nl_addr_clone(src->r_src))) + return -NLE_NOMEM; + + if (src->r_dst) + if (!(dst->r_dst = nl_addr_clone(src->r_dst))) + return -NLE_NOMEM; + + return 0; +} + +static struct nla_policy rule_policy[FRA_MAX+1] = { + [FRA_TABLE] = { .type = NLA_U32 }, + [FRA_IIFNAME] = { .type = NLA_STRING, .maxlen = IFNAMSIZ }, + [FRA_OIFNAME] = { .type = NLA_STRING, .maxlen = IFNAMSIZ }, + [FRA_PRIORITY] = { .type = NLA_U32 }, + [FRA_FWMARK] = { .type = NLA_U32 }, + [FRA_FWMASK] = { .type = NLA_U32 }, + [FRA_GOTO] = { .type = NLA_U32 }, + [FRA_FLOW] = { .type = NLA_U32 }, +}; + +static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *n, struct nl_parser_param *pp) +{ + struct rtnl_rule *rule; + struct fib_rule_hdr *frh; + struct nlattr *tb[FRA_MAX+1]; + int err = 1, family; + + rule = rtnl_rule_alloc(); + if (!rule) { + err = -NLE_NOMEM; + goto errout; + } + + rule->ce_msgtype = n->nlmsg_type; + frh = nlmsg_data(n); + + err = nlmsg_parse(n, sizeof(*frh), tb, FRA_MAX, rule_policy); + if (err < 0) + goto errout; + + rule->r_family = family = frh->family; + rule->r_table = frh->table; + rule->r_action = frh->action; + rule->r_flags = frh->flags; + + rule->ce_mask = (RULE_ATTR_FAMILY | RULE_ATTR_TABLE | RULE_ATTR_ACTION | + RULE_ATTR_FLAGS); + + /* ipv4 only */ + if (frh->tos) { + rule->r_dsfield = frh->tos; + rule->ce_mask |= RULE_ATTR_DSFIELD; + } + + if (tb[FRA_TABLE]) { + rule->r_table = nla_get_u32(tb[FRA_TABLE]); + rule->ce_mask |= RULE_ATTR_TABLE; + } + + if (tb[FRA_IIFNAME]) { + nla_strlcpy(rule->r_iifname, tb[FRA_IIFNAME], IFNAMSIZ); + rule->ce_mask |= RULE_ATTR_IIFNAME; + } + + if (tb[FRA_OIFNAME]) { + nla_strlcpy(rule->r_oifname, tb[FRA_OIFNAME], IFNAMSIZ); + rule->ce_mask |= RULE_ATTR_OIFNAME; + } + + if (tb[FRA_PRIORITY]) { + rule->r_prio = nla_get_u32(tb[FRA_PRIORITY]); + rule->ce_mask |= RULE_ATTR_PRIO; + } + + if (tb[FRA_FWMARK]) { + rule->r_mark = nla_get_u32(tb[FRA_FWMARK]); + rule->ce_mask |= RULE_ATTR_MARK; + } + + if (tb[FRA_FWMASK]) { + rule->r_mask = nla_get_u32(tb[FRA_FWMASK]); + rule->ce_mask |= RULE_ATTR_MASK; + } + + if (tb[FRA_GOTO]) { + rule->r_goto = nla_get_u32(tb[FRA_GOTO]); + rule->ce_mask |= RULE_ATTR_GOTO; + } + + if (tb[FRA_SRC]) { + if (!(rule->r_src = nl_addr_alloc_attr(tb[FRA_SRC], family))) + goto errout_enomem; + + nl_addr_set_prefixlen(rule->r_src, frh->src_len); + rule->ce_mask |= RULE_ATTR_SRC; + } + + if (tb[FRA_DST]) { + if (!(rule->r_dst = nl_addr_alloc_attr(tb[FRA_DST], family))) + goto errout_enomem; + nl_addr_set_prefixlen(rule->r_dst, frh->dst_len); + rule->ce_mask |= RULE_ATTR_DST; + } + + /* ipv4 only */ + if (tb[FRA_FLOW]) { + rule->r_flow = nla_get_u32(tb[FRA_FLOW]); + rule->ce_mask |= RULE_ATTR_FLOW; + } + + err = pp->pp_cb((struct nl_object *) rule, pp); +errout: + rtnl_rule_put(rule); + return err; + +errout_enomem: + err = -NLE_NOMEM; + goto errout; +} + +static int rule_request_update(struct nl_cache *c, struct nl_sock *h) +{ + return nl_rtgen_request(h, RTM_GETRULE, AF_UNSPEC, NLM_F_DUMP); +} + +static void rule_dump_line(struct nl_object *o, struct nl_dump_params *p) +{ + struct rtnl_rule *r = (struct rtnl_rule *) o; + char buf[128]; + + nl_dump_line(p, "%8d ", (r->ce_mask & RULE_ATTR_PRIO) ? r->r_prio : 0); + nl_dump(p, "%s ", nl_af2str(r->r_family, buf, sizeof(buf))); + + if (r->ce_mask & RULE_ATTR_SRC) + nl_dump(p, "from %s ", + nl_addr2str(r->r_src, buf, sizeof(buf))); + + if (r->ce_mask & RULE_ATTR_DST) + nl_dump(p, "to %s ", + nl_addr2str(r->r_dst, buf, sizeof(buf))); + + if (r->ce_mask & RULE_ATTR_DSFIELD) + nl_dump(p, "tos %u ", r->r_dsfield); + + if (r->ce_mask & (RULE_ATTR_MARK | RULE_ATTR_MASK)) + nl_dump(p, "mark %#x/%#x", r->r_mark, r->r_mask); + + if (r->ce_mask & RULE_ATTR_IIFNAME) + nl_dump(p, "iif %s ", r->r_iifname); + + if (r->ce_mask & RULE_ATTR_OIFNAME) + nl_dump(p, "oif %s ", r->r_oifname); + + if (r->ce_mask & RULE_ATTR_TABLE) + nl_dump(p, "lookup %s ", + rtnl_route_table2str(r->r_table, buf, sizeof(buf))); + + if (r->ce_mask & RULE_ATTR_FLOW) + nl_dump(p, "flow %s ", + rtnl_realms2str(r->r_flow, buf, sizeof(buf))); + + if (r->ce_mask & RULE_ATTR_GOTO) + nl_dump(p, "goto %u ", r->r_goto); + + if (r->ce_mask & RULE_ATTR_ACTION) + nl_dump(p, "action %s", + nl_rtntype2str(r->r_action, buf, sizeof(buf))); + + nl_dump(p, "\n"); +} + +static void rule_dump_details(struct nl_object *obj, struct nl_dump_params *p) +{ + rule_dump_line(obj, p); +} + +static void rule_dump_stats(struct nl_object *obj, struct nl_dump_params *p) +{ + rule_dump_details(obj, p); +} + +#define RULE_ATTR_FLAGS 0x0008 + +static int rule_compare(struct nl_object *_a, struct nl_object *_b, + uint32_t attrs, int flags) +{ + struct rtnl_rule *a = (struct rtnl_rule *) _a; + struct rtnl_rule *b = (struct rtnl_rule *) _b; + int diff = 0; + +#define RULE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, RULE_ATTR_##ATTR, a, b, EXPR) + + diff |= RULE_DIFF(FAMILY, a->r_family != b->r_family); + diff |= RULE_DIFF(TABLE, a->r_table != b->r_table); + diff |= RULE_DIFF(ACTION, a->r_action != b->r_action); + diff |= RULE_DIFF(IIFNAME, strcmp(a->r_iifname, b->r_iifname)); + diff |= RULE_DIFF(OIFNAME, strcmp(a->r_oifname, b->r_oifname)); + diff |= RULE_DIFF(PRIO, a->r_prio != b->r_prio); + diff |= RULE_DIFF(MARK, a->r_mark != b->r_mark); + diff |= RULE_DIFF(MASK, a->r_mask != b->r_mask); + diff |= RULE_DIFF(GOTO, a->r_goto != b->r_goto); + diff |= RULE_DIFF(SRC, nl_addr_cmp(a->r_src, b->r_src)); + diff |= RULE_DIFF(DST, nl_addr_cmp(a->r_dst, b->r_dst)); + diff |= RULE_DIFF(DSFIELD, a->r_dsfield != b->r_dsfield); + diff |= RULE_DIFF(FLOW, a->r_flow != b->r_flow); + +#undef RULE_DIFF + + return diff; +} + +static const struct trans_tbl rule_attrs[] = { + __ADD(RULE_ATTR_FAMILY, family) + __ADD(RULE_ATTR_TABLE, table) + __ADD(RULE_ATTR_ACTION, action) + __ADD(RULE_ATTR_IIFNAME, iifname) + __ADD(RULE_ATTR_OIFNAME, oifname) + __ADD(RULE_ATTR_PRIO, prio) + __ADD(RULE_ATTR_MARK, mark) + __ADD(RULE_ATTR_MASK, mask) + __ADD(RULE_ATTR_GOTO, goto) + __ADD(RULE_ATTR_SRC, src) + __ADD(RULE_ATTR_DST, dst) + __ADD(RULE_ATTR_DSFIELD, dsfield) + __ADD(RULE_ATTR_FLOW, flow) +}; + +static char *rule_attrs2str(int attrs, char *buf, size_t len) +{ + return __flags2str(attrs, buf, len, rule_attrs, + ARRAY_SIZE(rule_attrs)); +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct rtnl_rule *rtnl_rule_alloc(void) +{ + return (struct rtnl_rule *) nl_object_alloc(&rule_obj_ops); +} + +void rtnl_rule_put(struct rtnl_rule *rule) +{ + nl_object_put((struct nl_object *) rule); +} + +/** @} */ + +/** + * @name Cache Management + * @{ + */ + +/** + * Build a rule cache including all rules currently configured in the kernel. + * @arg sock Netlink socket. + * @arg family Address family or AF_UNSPEC. + * @arg result Pointer to store resulting cache. + * + * Allocates a new rule cache, initializes it properly and updates it + * to include all rules currently configured in the kernel. + * + * @return 0 on success or a negative error code. + */ +int rtnl_rule_alloc_cache(struct nl_sock *sock, int family, + struct nl_cache **result) +{ + struct nl_cache * cache; + int err; + + if (!(cache = nl_cache_alloc(&rtnl_rule_ops))) + return -NLE_NOMEM; + + cache->c_iarg1 = family; + + if (sock && (err = nl_cache_refill(sock, cache)) < 0) { + free(cache); + return err; + } + + *result = cache; + return 0; +} + +/** @} */ + +/** + * @name Rule Addition + * @{ + */ + +static int build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags, + struct nl_msg **result) +{ + struct nl_msg *msg; + struct fib_rule_hdr frh = { + .family = tmpl->r_family, + .table = tmpl->r_table, + .action = tmpl->r_action, + .flags = tmpl->r_flags, + .tos = tmpl->r_dsfield, + }; + + if (!(tmpl->ce_mask & RULE_ATTR_FAMILY)) + return -NLE_MISSING_ATTR; + + msg = nlmsg_alloc_simple(cmd, flags); + if (!msg) + return -NLE_NOMEM; + + if (tmpl->ce_mask & RULE_ATTR_SRC) + frh.src_len = nl_addr_get_prefixlen(tmpl->r_src); + + if (tmpl->ce_mask & RULE_ATTR_DST) + frh.dst_len = nl_addr_get_prefixlen(tmpl->r_dst); + + if (nlmsg_append(msg, &frh, sizeof(frh), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + if (tmpl->ce_mask & RULE_ATTR_SRC) + NLA_PUT_ADDR(msg, FRA_SRC, tmpl->r_src); + + if (tmpl->ce_mask & RULE_ATTR_DST) + NLA_PUT_ADDR(msg, FRA_DST, tmpl->r_dst); + + if (tmpl->ce_mask & RULE_ATTR_IIFNAME) + NLA_PUT_STRING(msg, FRA_IIFNAME, tmpl->r_iifname); + + if (tmpl->ce_mask & RULE_ATTR_OIFNAME) + NLA_PUT_STRING(msg, FRA_OIFNAME, tmpl->r_oifname); + + if (tmpl->ce_mask & RULE_ATTR_PRIO) + NLA_PUT_U32(msg, FRA_PRIORITY, tmpl->r_prio); + + if (tmpl->ce_mask & RULE_ATTR_MARK) + NLA_PUT_U32(msg, FRA_FWMARK, tmpl->r_mark); + + if (tmpl->ce_mask & RULE_ATTR_MASK) + NLA_PUT_U32(msg, FRA_FWMASK, tmpl->r_mask); + + if (tmpl->ce_mask & RULE_ATTR_GOTO) + NLA_PUT_U32(msg, FRA_GOTO, tmpl->r_goto); + + if (tmpl->ce_mask & RULE_ATTR_FLOW) + NLA_PUT_U32(msg, FRA_FLOW, tmpl->r_flow); + + + *result = msg; + return 0; + +nla_put_failure: + nlmsg_free(msg); + return -NLE_MSGSIZE; +} + +/** + * Build netlink request message to add a new rule + * @arg tmpl template with data of new rule + * @arg flags additional netlink message flags + * @arg result Result pointer + * + * Builds a new netlink message requesting a addition of a new + * rule. The netlink message header isn't fully equipped with + * all relevant fields and must thus be sent out via nl_send_auto_complete() + * or supplemented as needed. \a tmpl must contain the attributes of the new + * address set via \c rtnl_rule_set_* functions. + * + * @return 0 on success or a negative error code. + */ +int rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags, + struct nl_msg **result) +{ + return build_rule_msg(tmpl, RTM_NEWRULE, NLM_F_CREATE | flags, + result); +} + +/** + * Add a new rule + * @arg sk Netlink socket. + * @arg tmpl template with requested changes + * @arg flags additional netlink message flags + * + * Builds a netlink message by calling rtnl_rule_build_add_request(), + * sends the request to the kernel and waits for the next ACK to be + * received and thus blocks until the request has been fullfilled. + * + * @return 0 on sucess or a negative error if an error occured. + */ +int rtnl_rule_add(struct nl_sock *sk, struct rtnl_rule *tmpl, int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_rule_build_add_request(tmpl, flags, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +/** @} */ + +/** + * @name Rule Deletion + * @{ + */ + +/** + * Build a netlink request message to delete a rule + * @arg rule rule to delete + * @arg flags additional netlink message flags + * @arg result Result pointer + * + * Builds a new netlink message requesting a deletion of a rule. + * The netlink message header isn't fully equipped with all relevant + * fields and must thus be sent out via nl_send_auto_complete() + * or supplemented as needed. \a rule must point to an existing + * address. + * + * @return 0 on success or a negative error code. + */ +int rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags, + struct nl_msg **result) +{ + return build_rule_msg(rule, RTM_DELRULE, flags, result); +} + +/** + * Delete a rule + * @arg sk Netlink socket. + * @arg rule rule to delete + * @arg flags additional netlink message flags + * + * Builds a netlink message by calling rtnl_rule_build_delete_request(), + * sends the request to the kernel and waits for the next ACK to be + * received and thus blocks until the request has been fullfilled. + * + * @return 0 on sucess or a negative error if an error occured. + */ +int rtnl_rule_delete(struct nl_sock *sk, struct rtnl_rule *rule, int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_rule_build_delete_request(rule, flags, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +/** @} */ + +/** + * @name Attribute Modification + * @{ + */ + +void rtnl_rule_set_family(struct rtnl_rule *rule, int family) +{ + rule->r_family = family; + rule->ce_mask |= RULE_ATTR_FAMILY; +} + +int rtnl_rule_get_family(struct rtnl_rule *rule) +{ + if (rule->ce_mask & RULE_ATTR_FAMILY) + return rule->r_family; + else + return AF_UNSPEC; +} + +void rtnl_rule_set_prio(struct rtnl_rule *rule, uint32_t prio) +{ + rule->r_prio = prio; + rule->ce_mask |= RULE_ATTR_PRIO; +} + +uint32_t rtnl_rule_get_prio(struct rtnl_rule *rule) +{ + return rule->r_prio; +} + +void rtnl_rule_set_mark(struct rtnl_rule *rule, uint32_t mark) +{ + rule->r_mark = mark; + rule->ce_mask |= RULE_ATTR_MARK; +} + +uint32_t rtnl_rule_get_mark(struct rtnl_rule *rule) +{ + return rule->r_mark; +} + +void rtnl_rule_set_mask(struct rtnl_rule *rule, uint32_t mask) +{ + rule->r_mask = mask; + rule->ce_mask |= RULE_ATTR_MASK; +} + +uint32_t rtnl_rule_get_mask(struct rtnl_rule *rule) +{ + return rule->r_mask; +} + +void rtnl_rule_set_table(struct rtnl_rule *rule, uint32_t table) +{ + rule->r_table = table; + rule->ce_mask |= RULE_ATTR_TABLE; +} + +uint32_t rtnl_rule_get_table(struct rtnl_rule *rule) +{ + return rule->r_table; +} + +void rtnl_rule_set_dsfield(struct rtnl_rule *rule, uint8_t dsfield) +{ + rule->r_dsfield = dsfield; + rule->ce_mask |= RULE_ATTR_DSFIELD; +} + +uint8_t rtnl_rule_get_dsfield(struct rtnl_rule *rule) +{ + return rule->r_dsfield; +} + +static inline int __assign_addr(struct rtnl_rule *rule, struct nl_addr **pos, + struct nl_addr *new, int flag) +{ + if (rule->ce_mask & RULE_ATTR_FAMILY) { + if (new->a_family != rule->r_family) + return -NLE_AF_MISMATCH; + } else + rule->r_family = new->a_family; + + if (*pos) + nl_addr_put(*pos); + + nl_addr_get(new); + *pos = new; + + rule->ce_mask |= (flag | RULE_ATTR_FAMILY); + + return 0; +} + +int rtnl_rule_set_src(struct rtnl_rule *rule, struct nl_addr *src) +{ + return __assign_addr(rule, &rule->r_src, src, RULE_ATTR_SRC); +} + +struct nl_addr *rtnl_rule_get_src(struct rtnl_rule *rule) +{ + return rule->r_src; +} + +int rtnl_rule_set_dst(struct rtnl_rule *rule, struct nl_addr *dst) +{ + return __assign_addr(rule, &rule->r_dst, dst, RULE_ATTR_DST); +} + +struct nl_addr *rtnl_rule_get_dst(struct rtnl_rule *rule) +{ + return rule->r_dst; +} + +int rtnl_rule_set_iif(struct rtnl_rule *rule, const char *dev) +{ + if (strlen(dev) > IFNAMSIZ-1) + return -NLE_RANGE; + + strcpy(rule->r_iifname, dev); + rule->ce_mask |= RULE_ATTR_IIFNAME; + return 0; +} + +char *rtnl_rule_get_iif(struct rtnl_rule *rule) +{ + if (rule->ce_mask & RULE_ATTR_IIFNAME) + return rule->r_iifname; + else + return NULL; +} + +int rtnl_rule_set_oif(struct rtnl_rule *rule, const char *dev) +{ + if (strlen(dev) > IFNAMSIZ-1) + return -NLE_RANGE; + + strcpy(rule->r_oifname, dev); + rule->ce_mask |= RULE_ATTR_OIFNAME; + return 0; +} + +char *rtnl_rule_get_oif(struct rtnl_rule *rule) +{ + if (rule->ce_mask & RULE_ATTR_OIFNAME) + return rule->r_oifname; + else + return NULL; +} + +void rtnl_rule_set_action(struct rtnl_rule *rule, uint8_t action) +{ + rule->r_action = action; + rule->ce_mask |= RULE_ATTR_ACTION; +} + +uint8_t rtnl_rule_get_action(struct rtnl_rule *rule) +{ + return rule->r_action; +} + +void rtnl_rule_set_realms(struct rtnl_rule *rule, uint32_t realms) +{ + rule->r_flow = realms; + rule->ce_mask |= RULE_ATTR_FLOW; +} + +uint32_t rtnl_rule_get_realms(struct rtnl_rule *rule) +{ + return rule->r_flow; +} + +void rtnl_rule_set_goto(struct rtnl_rule *rule, uint32_t ref) +{ + rule->r_goto = ref; + rule->ce_mask |= RULE_ATTR_GOTO; +} + +uint32_t rtnl_rule_get_goto(struct rtnl_rule *rule) +{ + return rule->r_goto; +} + +/** @} */ + +static struct nl_object_ops rule_obj_ops = { + .oo_name = "route/rule", + .oo_size = sizeof(struct rtnl_rule), + .oo_free_data = rule_free_data, + .oo_clone = rule_clone, + .oo_dump = { + [NL_DUMP_LINE] = rule_dump_line, + [NL_DUMP_DETAILS] = rule_dump_details, + [NL_DUMP_STATS] = rule_dump_stats, + }, + .oo_compare = rule_compare, + .oo_attrs2str = rule_attrs2str, + .oo_id_attrs = ~0, +}; + +static struct nl_cache_ops rtnl_rule_ops = { + .co_name = "route/rule", + .co_hdrsize = sizeof(struct fib_rule_hdr), + .co_msgtypes = { + { RTM_NEWRULE, NL_ACT_NEW, "new" }, + { RTM_DELRULE, NL_ACT_DEL, "del" }, + { RTM_GETRULE, NL_ACT_GET, "get" }, + END_OF_MSGTYPES_LIST, + }, + .co_protocol = NETLINK_ROUTE, + .co_request_update = rule_request_update, + .co_msg_parser = rule_msg_parser, + .co_obj_ops = &rule_obj_ops, +}; + +static void __init rule_init(void) +{ + nl_cache_mngt_register(&rtnl_rule_ops); +} + +static void __exit rule_exit(void) +{ + nl_cache_mngt_unregister(&rtnl_rule_ops); +} + +/** @} */ diff --git a/libnetwork/libnl3/lib/route/tc.c b/libnetwork/libnl3/lib/route/tc.c new file mode 100644 index 0000000..6826a05 --- /dev/null +++ b/libnetwork/libnl3/lib/route/tc.c @@ -0,0 +1,1069 @@ +/* + * lib/route/tc.c Traffic Control + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2011 Thomas Graf + */ + +/** + * @ingroup rtnl + * @defgroup tc Traffic Control + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ + +static struct nl_list_head tc_ops_list[__RTNL_TC_TYPE_MAX]; +static struct rtnl_tc_type_ops *tc_type_ops[__RTNL_TC_TYPE_MAX]; + +static struct nla_policy tc_policy[TCA_MAX+1] = { + [TCA_KIND] = { .type = NLA_STRING, + .maxlen = TCKINDSIZ }, + [TCA_STATS] = { .minlen = sizeof(struct tc_stats) }, + [TCA_STATS2] = { .type = NLA_NESTED }, +}; + +int tca_parse(struct nlattr **tb, int maxattr, struct rtnl_tc *g, + struct nla_policy *policy) +{ + + if (g->ce_mask & TCA_ATTR_OPTS) + return nla_parse(tb, maxattr, + (struct nlattr *) g->tc_opts->d_data, + g->tc_opts->d_size, policy); + else { + /* Ugly but tb[] must be in a defined state even if no + * attributes can be found. */ + memset(tb, 0, sizeof(struct nlattr *) * (maxattr + 1)); + return 0; + } +} + +static struct nla_policy tc_stats2_policy[TCA_STATS_MAX+1] = { + [TCA_STATS_BASIC] = { .minlen = sizeof(struct gnet_stats_basic) }, + [TCA_STATS_RATE_EST] = { .minlen = sizeof(struct gnet_stats_rate_est) }, + [TCA_STATS_QUEUE] = { .minlen = sizeof(struct gnet_stats_queue) }, +}; + +int rtnl_tc_msg_parse(struct nlmsghdr *n, struct rtnl_tc *tc) +{ + struct nl_cache *link_cache; + struct rtnl_tc_ops *ops; + struct nlattr *tb[TCA_MAX + 1]; + char kind[TCKINDSIZ]; + struct tcmsg *tm; + int err; + + tc->ce_msgtype = n->nlmsg_type; + + err = nlmsg_parse(n, sizeof(*tm), tb, TCA_MAX, tc_policy); + if (err < 0) + return err; + + if (tb[TCA_KIND] == NULL) + return -NLE_MISSING_ATTR; + + nla_strlcpy(kind, tb[TCA_KIND], sizeof(kind)); + rtnl_tc_set_kind(tc, kind); + + tm = nlmsg_data(n); + tc->tc_family = tm->tcm_family; + tc->tc_ifindex = tm->tcm_ifindex; + tc->tc_handle = tm->tcm_handle; + tc->tc_parent = tm->tcm_parent; + tc->tc_info = tm->tcm_info; + + tc->ce_mask |= (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE| + TCA_ATTR_PARENT | TCA_ATTR_INFO); + + if (tb[TCA_OPTIONS]) { + tc->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]); + if (!tc->tc_opts) + return -NLE_NOMEM; + tc->ce_mask |= TCA_ATTR_OPTS; + } + + if (tb[TCA_STATS2]) { + struct nlattr *tbs[TCA_STATS_MAX + 1]; + + err = nla_parse_nested(tbs, TCA_STATS_MAX, tb[TCA_STATS2], + tc_stats2_policy); + if (err < 0) + return err; + + if (tbs[TCA_STATS_BASIC]) { + struct gnet_stats_basic *bs; + + bs = nla_data(tbs[TCA_STATS_BASIC]); + tc->tc_stats[RTNL_TC_BYTES] = bs->bytes; + tc->tc_stats[RTNL_TC_PACKETS] = bs->packets; + } + + if (tbs[TCA_STATS_RATE_EST]) { + struct gnet_stats_rate_est *re; + + re = nla_data(tbs[TCA_STATS_RATE_EST]); + tc->tc_stats[RTNL_TC_RATE_BPS] = re->bps; + tc->tc_stats[RTNL_TC_RATE_PPS] = re->pps; + } + + if (tbs[TCA_STATS_QUEUE]) { + struct gnet_stats_queue *q; + + q = nla_data(tbs[TCA_STATS_QUEUE]); + tc->tc_stats[RTNL_TC_QLEN] = q->qlen; + tc->tc_stats[RTNL_TC_BACKLOG] = q->backlog; + tc->tc_stats[RTNL_TC_DROPS] = q->drops; + tc->tc_stats[RTNL_TC_REQUEUES] = q->requeues; + tc->tc_stats[RTNL_TC_OVERLIMITS] = q->overlimits; + } + + tc->ce_mask |= TCA_ATTR_STATS; + + if (tbs[TCA_STATS_APP]) { + tc->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]); + if (tc->tc_xstats == NULL) + return -NLE_NOMEM; + } else + goto compat_xstats; + } else { + if (tb[TCA_STATS]) { + struct tc_stats *st = nla_data(tb[TCA_STATS]); + + tc->tc_stats[RTNL_TC_BYTES] = st->bytes; + tc->tc_stats[RTNL_TC_PACKETS] = st->packets; + tc->tc_stats[RTNL_TC_RATE_BPS] = st->bps; + tc->tc_stats[RTNL_TC_RATE_PPS] = st->pps; + tc->tc_stats[RTNL_TC_QLEN] = st->qlen; + tc->tc_stats[RTNL_TC_BACKLOG] = st->backlog; + tc->tc_stats[RTNL_TC_DROPS] = st->drops; + tc->tc_stats[RTNL_TC_OVERLIMITS]= st->overlimits; + + tc->ce_mask |= TCA_ATTR_STATS; + } + +compat_xstats: + if (tb[TCA_XSTATS]) { + tc->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]); + if (tc->tc_xstats == NULL) + return -NLE_NOMEM; + tc->ce_mask |= TCA_ATTR_XSTATS; + } + } + + ops = rtnl_tc_get_ops(tc); + if (ops && ops->to_msg_parser) { + void *data = rtnl_tc_data(tc); + + if (!data) + return -NLE_NOMEM; + + err = ops->to_msg_parser(tc, data); + if (err < 0) + return err; + } + + if ((link_cache = __nl_cache_mngt_require("route/link"))) { + struct rtnl_link *link; + + if ((link = rtnl_link_get(link_cache, tc->tc_ifindex))) { + rtnl_tc_set_link(tc, link); + + /* rtnl_tc_set_link incs refcnt */ + rtnl_link_put(link); + } + } + + return 0; +} + +int rtnl_tc_msg_build(struct rtnl_tc *tc, int type, int flags, + struct nl_msg **result) +{ + struct nl_msg *msg; + struct rtnl_tc_ops *ops; + struct tcmsg tchdr = { + .tcm_family = AF_UNSPEC, + .tcm_ifindex = tc->tc_ifindex, + .tcm_handle = tc->tc_handle, + .tcm_parent = tc->tc_parent, + }; + int err = -NLE_MSGSIZE; + + msg = nlmsg_alloc_simple(type, flags); + if (!msg) + return -NLE_NOMEM; + + if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + if (tc->ce_mask & TCA_ATTR_KIND) + NLA_PUT_STRING(msg, TCA_KIND, tc->tc_kind); + + ops = rtnl_tc_get_ops(tc); + if (ops && ops->to_msg_fill) { + struct nlattr *opts; + void *data = rtnl_tc_data(tc); + + if (!(opts = nla_nest_start(msg, TCA_OPTIONS))) + goto nla_put_failure; + + if ((err = ops->to_msg_fill(tc, data, msg)) < 0) + goto nla_put_failure; + + nla_nest_end(msg, opts); + } + + *result = msg; + return 0; + +nla_put_failure: + nlmsg_free(msg); + return err; +} + +void tca_set_kind(struct rtnl_tc *t, const char *kind) +{ + strncpy(t->tc_kind, kind, sizeof(t->tc_kind) - 1); + t->ce_mask |= TCA_ATTR_KIND; +} + + +/** @endcond */ + +/** + * @name Attributes + * @{ + */ + +/** + * Set interface index of traffic control object + * @arg tc traffic control object + * @arg ifindex interface index. + * + * Sets the interface index of a traffic control object. The interface + * index defines the network device which this tc object is attached to. + * This function will overwrite any network device assigned with previous + * calls to rtnl_tc_set_ifindex() or rtnl_tc_set_link(). + */ +void rtnl_tc_set_ifindex(struct rtnl_tc *tc, int ifindex) +{ + /* Obsolete possible old link reference */ + rtnl_link_put(tc->tc_link); + tc->tc_link = NULL; + tc->ce_mask &= ~TCA_ATTR_LINK; + + tc->tc_ifindex = ifindex; + tc->ce_mask |= TCA_ATTR_IFINDEX; +} + +/** + * Return interface index of traffic control object + * @arg tc traffic control object + */ +int rtnl_tc_get_ifindex(struct rtnl_tc *tc) +{ + return tc->tc_ifindex; +} + +/** + * Set link of traffic control object + * @arg tc traffic control object + * @arg link link object + * + * Sets the link of a traffic control object. This function serves + * the same purpose as rtnl_tc_set_ifindex() but due to the continued + * allowed access to the link object it gives it the possibility to + * retrieve sane default values for the the MTU and the linktype. + * Always prefer this function over rtnl_tc_set_ifindex() if you can + * spare to have an additional link object around. + */ +void rtnl_tc_set_link(struct rtnl_tc *tc, struct rtnl_link *link) +{ + rtnl_link_put(tc->tc_link); + + if (!link) + return; + + nl_object_get(OBJ_CAST(link)); + tc->tc_link = link; + tc->tc_ifindex = link->l_index; + tc->ce_mask |= TCA_ATTR_LINK | TCA_ATTR_IFINDEX; +} + +/** + * Get link of traffic control object + * @arg tc traffic control object + * + * Returns the link of a traffic control object. The link is only + * returned if it has been set before via rtnl_tc_set_link() or + * if a link cache was available while parsing the tc object. This + * function may still return NULL even if an ifindex is assigned to + * the tc object. It will _not_ look up the link by itself. + * + * @note The returned link will have its reference counter incremented. + * It is in the responsibility of the caller to return the + * reference. + * + * @return link object or NULL if not set. + */ +struct rtnl_link *rtnl_tc_get_link(struct rtnl_tc *tc) +{ + if (tc->tc_link) { + nl_object_get(OBJ_CAST(tc->tc_link)); + return tc->tc_link; + } + + return NULL; +} + +/** + * Set the Maximum Transmission Unit (MTU) of traffic control object + * @arg tc traffic control object + * @arg mtu largest packet size expected + * + * Sets the MTU of a traffic control object. Not all traffic control + * objects will make use of this but it helps while calculating rate + * tables. This value is typically derived directly from the link + * the tc object is attached to if the link has been assigned via + * rtnl_tc_set_link(). It is usually not necessary to set the MTU + * manually, this function is provided to allow overwriting the derived + * value. + */ +void rtnl_tc_set_mtu(struct rtnl_tc *tc, uint32_t mtu) +{ + tc->tc_mtu = mtu; + tc->ce_mask |= TCA_ATTR_MTU; +} + +/** + * Return the MTU of traffic control object + * @arg tc traffic control object + * + * Returns the MTU of a traffic control object which has been set via: + * -# User specified value set via rtnl_tc_set_mtu() + * -# Dervied from link set via rtnl_tc_set_link() + * -# Fall back to default: ethernet = 1500 + */ +uint32_t rtnl_tc_get_mtu(struct rtnl_tc *tc) +{ + if (tc->ce_mask & TCA_ATTR_MTU) + return tc->tc_mtu; + else if (tc->ce_mask & TCA_ATTR_LINK) + return tc->tc_link->l_mtu; + else + return 1500; /* default to ethernet */ +} + +/** + * Set the Minimum Packet Unit (MPU) of a traffic control object + * @arg tc traffic control object + * @arg mpu minimum packet size expected + * + * Sets the MPU of a traffic contorl object. It specifies the minimum + * packet size to ever hit this traffic control object. Not all traffic + * control objects will make use of this but it helps while calculating + * rate tables. + */ +void rtnl_tc_set_mpu(struct rtnl_tc *tc, uint32_t mpu) +{ + tc->tc_mpu = mpu; + tc->ce_mask |= TCA_ATTR_MPU; +} + +/** + * Return the Minimum Packet Unit (MPU) of a traffic control object + * @arg tc traffic control object + * + * @return The MPU previously set via rtnl_tc_set_mpu() or 0. + */ +uint32_t rtnl_tc_get_mpu(struct rtnl_tc *tc) +{ + return tc->tc_mpu; +} + +/** + * Set per packet overhead of a traffic control object + * @arg tc traffic control object + * @arg overhead overhead per packet in bytes + * + * Sets the per packet overhead in bytes occuring on the link not seen + * by the kernel. This value can be used to correct size calculations + * if the packet size on the wire does not match the packet sizes seen + * in the network stack. Not all traffic control objects will make use + * this but it helps while calculating accurate packet sizes in the + * kernel. + */ +void rtnl_tc_set_overhead(struct rtnl_tc *tc, uint32_t overhead) +{ + tc->tc_overhead = overhead; + tc->ce_mask |= TCA_ATTR_OVERHEAD; +} + +/** + * Return per packet overhead of a traffic control object + * @arg tc traffic control object + * + * @return The overhead previously set by rtnl_tc_set_overhead() or 0. + */ +uint32_t rtnl_tc_get_overhead(struct rtnl_tc *tc) +{ + return tc->tc_overhead; +} + +/** + * Set the linktype of a traffic control object + * @arg tc traffic control object + * @arg type type of link (e.g. ARPHRD_ATM, ARPHRD_ETHER) + * + * Overwrites the type of link this traffic control object is attached to. + * This value is typically derived from the link this tc object is attached + * if the link has been assigned via rtnl_tc_set_link(). It is usually not + * necessary to set the linktype manually. This function is provided to + * allow overwriting the linktype. + */ +void rtnl_tc_set_linktype(struct rtnl_tc *tc, uint32_t type) +{ + tc->tc_linktype = type; + tc->ce_mask |= TCA_ATTR_LINKTYPE; +} + +/** + * Return the linktype of a traffic control object + * @arg tc traffic control object + * + * Returns the linktype of the link the traffic control object is attached to: + * -# User specified value via rtnl_tc_set_linktype() + * -# Value derived from link set via rtnl_tc_set_link() + * -# Default fall-back: ARPHRD_ETHER + */ +uint32_t rtnl_tc_get_linktype(struct rtnl_tc *tc) +{ + if (tc->ce_mask & TCA_ATTR_LINKTYPE) + return tc->tc_linktype; + else if (tc->ce_mask & TCA_ATTR_LINK) + return tc->tc_link->l_arptype; + else + return ARPHRD_ETHER; /* default to ethernet */ +} + +/** + * Set identifier of traffic control object + * @arg tc traffic control object + * @arg id unique identifier + */ +void rtnl_tc_set_handle(struct rtnl_tc *tc, uint32_t id) +{ + tc->tc_handle = id; + tc->ce_mask |= TCA_ATTR_HANDLE; +} + +/** + * Return identifier of a traffic control object + * @arg tc traffic control object + */ +uint32_t rtnl_tc_get_handle(struct rtnl_tc *tc) +{ + return tc->tc_handle; +} + +/** + * Set the parent identifier of a traffic control object + * @arg tc traffic control object + * @arg parent identifier of parent traffif control object + * + */ +void rtnl_tc_set_parent(struct rtnl_tc *tc, uint32_t parent) +{ + tc->tc_parent = parent; + tc->ce_mask |= TCA_ATTR_PARENT; +} + +/** + * Return parent identifier of a traffic control object + * @arg tc traffic control object + */ +uint32_t rtnl_tc_get_parent(struct rtnl_tc *tc) +{ + return tc->tc_parent; +} + +/** + * Define the type of traffic control object + * @arg tc traffic control object + * @arg kind name of the tc object type + * + * @return 0 on success or a negative error code + */ +int rtnl_tc_set_kind(struct rtnl_tc *tc, const char *kind) +{ + if (tc->ce_mask & TCA_ATTR_KIND) + return -NLE_EXIST; + + strncpy(tc->tc_kind, kind, sizeof(tc->tc_kind) - 1); + tc->ce_mask |= TCA_ATTR_KIND; + + /* Force allocation of data */ + rtnl_tc_data(tc); + + return 0; +} + +/** + * Return kind of traffic control object + * @arg tc traffic control object + * + * @return Kind of traffic control object or NULL if not set. + */ +char *rtnl_tc_get_kind(struct rtnl_tc *tc) +{ + if (tc->ce_mask & TCA_ATTR_KIND) + return tc->tc_kind; + else + return NULL; +} + +/** + * Return value of a statistical counter of a traffic control object + * @arg tc traffic control object + * @arg id identifier of statistical counter + * + * @return Value of requested statistic counter or 0. + */ +uint64_t rtnl_tc_get_stat(struct rtnl_tc *tc, enum rtnl_tc_stat id) +{ + if (id < 0 || id > RTNL_TC_STATS_MAX) + return 0; + + return tc->tc_stats[id]; +} + +/** @} */ + +/** + * @name Utilities + * @{ + */ + +/** + * Calculate time required to transmit buffer at a specific rate + * @arg bufsize Size of buffer to be transmited in bytes. + * @arg rate Transmit rate in bytes per second. + * + * Calculates the number of micro seconds required to transmit a + * specific buffer at a specific transmit rate. + * + * @f[ + * txtime=\frac{bufsize}{rate}10^6 + * @f] + * + * @return Required transmit time in micro seconds. + */ +int rtnl_tc_calc_txtime(int bufsize, int rate) +{ + double tx_time_secs; + + tx_time_secs = (double) bufsize / (double) rate; + + return tx_time_secs * 1000000.; +} + +/** + * Calculate buffer size able to transmit in a specific time and rate. + * @arg txtime Available transmit time in micro seconds. + * @arg rate Transmit rate in bytes per second. + * + * Calculates the size of the buffer that can be transmitted in a + * specific time period at a specific transmit rate. + * + * @f[ + * bufsize=\frac{{txtime} \times {rate}}{10^6} + * @f] + * + * @return Size of buffer in bytes. + */ +int rtnl_tc_calc_bufsize(int txtime, int rate) +{ + double bufsize; + + bufsize = (double) txtime * (double) rate; + + return bufsize / 1000000.; +} + +/** + * Calculate the binary logarithm for a specific cell size + * @arg cell_size Size of cell, must be a power of two. + * @return Binary logirhtm of cell size or a negative error code. + */ +int rtnl_tc_calc_cell_log(int cell_size) +{ + int i; + + for (i = 0; i < 32; i++) + if ((1 << i) == cell_size) + return i; + + return -NLE_INVAL; +} + + +/** @} */ + +/** + * @name Rate Tables + * @{ + */ + +/* + * COPYRIGHT NOTE: + * align_to_atm() and adjust_size() derived/coped from iproute2 source. + */ + +/* + * The align to ATM cells is used for determining the (ATM) SAR + * alignment overhead at the ATM layer. (SAR = Segmentation And + * Reassembly). This is for example needed when scheduling packet on + * an ADSL connection. Note that the extra ATM-AAL overhead is _not_ + * included in this calculation. This overhead is added in the kernel + * before doing the rate table lookup, as this gives better precision + * (as the table will always be aligned for 48 bytes). + * --Hawk, d.7/11-2004. + */ +static unsigned int align_to_atm(unsigned int size) +{ + int linksize, cells; + cells = size / ATM_CELL_PAYLOAD; + if ((size % ATM_CELL_PAYLOAD) > 0) + cells++; + + linksize = cells * ATM_CELL_SIZE; /* Use full cell size to add ATM tax */ + return linksize; +} + +static unsigned int adjust_size(unsigned int size, unsigned int mpu, + uint32_t linktype) +{ + if (size < mpu) + size = mpu; + + switch (linktype) { + case ARPHRD_ATM: + return align_to_atm(size); + + case ARPHRD_ETHER: + default: + return size; + } +} + +/** + * Compute a transmission time lookup table + * @arg tc traffic control object + * @arg spec Rate specification + * @arg dst Destination buffer of RTNL_TC_RTABLE_SIZE uint32_t[]. + * + * Computes a table of RTNL_TC_RTABLE_SIZE entries specyfing the + * transmission times for various packet sizes, e.g. the transmission + * time for a packet of size \c pktsize could be looked up: + * @code + * txtime = table[pktsize >> log2(mtu)]; + * @endcode + */ +int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *spec, + uint32_t *dst) +{ + uint32_t mtu = rtnl_tc_get_mtu(tc); + uint32_t linktype = rtnl_tc_get_linktype(tc); + uint8_t cell_log = spec->rs_cell_log; + unsigned int size, i; + + spec->rs_mpu = rtnl_tc_get_mpu(tc); + spec->rs_overhead = rtnl_tc_get_overhead(tc); + + if (mtu == 0) + mtu = 2047; + + if (cell_log == UINT8_MAX) { + /* + * cell_log not specified, calculate it. It has to specify the + * minimum number of rshifts required to break the MTU to below + * RTNL_TC_RTABLE_SIZE. + */ + cell_log = 0; + while ((mtu >> cell_log) >= RTNL_TC_RTABLE_SIZE) + cell_log++; + } + + for (i = 0; i < RTNL_TC_RTABLE_SIZE; i++) { + size = adjust_size((i + 1) << cell_log, spec->rs_mpu, linktype); + dst[i] = rtnl_tc_calc_txtime(size, spec->rs_rate); + } + + spec->rs_cell_align = -1; + spec->rs_cell_log = cell_log; + + return 0; +} + +/** @} */ + +/** + * @name TC implementation of cache functions + */ + +void rtnl_tc_free_data(struct nl_object *obj) +{ + struct rtnl_tc *tc = TC_CAST(obj); + struct rtnl_tc_ops *ops; + + rtnl_link_put(tc->tc_link); + nl_data_free(tc->tc_opts); + nl_data_free(tc->tc_xstats); + + if (tc->tc_subdata) { + ops = rtnl_tc_get_ops(tc); + if (ops && ops->to_free_data) + ops->to_free_data(tc, nl_data_get(tc->tc_subdata)); + + nl_data_free(tc->tc_subdata); + } +} + +int rtnl_tc_clone(struct nl_object *dstobj, struct nl_object *srcobj) +{ + struct rtnl_tc *dst = TC_CAST(dstobj); + struct rtnl_tc *src = TC_CAST(srcobj); + struct rtnl_tc_ops *ops; + + if (src->tc_link) { + nl_object_get(OBJ_CAST(src->tc_link)); + dst->tc_link = src->tc_link; + } + + if (src->tc_opts) { + dst->tc_opts = nl_data_clone(src->tc_opts); + if (!dst->tc_opts) + return -NLE_NOMEM; + } + + if (src->tc_xstats) { + dst->tc_xstats = nl_data_clone(src->tc_xstats); + if (!dst->tc_xstats) + return -NLE_NOMEM; + } + + if (src->tc_subdata) { + if (!(dst->tc_subdata = nl_data_clone(src->tc_subdata))) { + return -NLE_NOMEM; + } + } + + ops = rtnl_tc_get_ops(src); + if (ops && ops->to_clone) { + void *a = rtnl_tc_data(dst), *b = rtnl_tc_data(src); + + if (!a) + return 0; + else if (!b) + return -NLE_NOMEM; + + return ops->to_clone(a, b); + } + + return 0; +} + +static int tc_dump(struct rtnl_tc *tc, enum nl_dump_type type, + struct nl_dump_params *p) +{ + struct rtnl_tc_type_ops *type_ops; + struct rtnl_tc_ops *ops; + void *data = rtnl_tc_data(tc); + + type_ops = tc_type_ops[tc->tc_type]; + if (type_ops && type_ops->tt_dump[type]) + type_ops->tt_dump[type](tc, p); + + ops = rtnl_tc_get_ops(tc); + if (ops && ops->to_dump[type]) { + ops->to_dump[type](tc, data, p); + return 1; + } + + return 0; +} + +void rtnl_tc_dump_line(struct nl_object *obj, struct nl_dump_params *p) +{ + struct rtnl_tc_type_ops *type_ops; + struct rtnl_tc *tc = TC_CAST(obj); + struct nl_cache *link_cache; + char buf[32]; + + nl_new_line(p); + + type_ops = tc_type_ops[tc->tc_type]; + if (type_ops && type_ops->tt_dump_prefix) + nl_dump(p, "%s ", type_ops->tt_dump_prefix); + + nl_dump(p, "%s ", tc->tc_kind); + + if ((link_cache = nl_cache_mngt_require("route/link"))) { + nl_dump(p, "dev %s ", + rtnl_link_i2name(link_cache, tc->tc_ifindex, + buf, sizeof(buf))); + } else + nl_dump(p, "dev %u ", tc->tc_ifindex); + + nl_dump(p, "id %s ", + rtnl_tc_handle2str(tc->tc_handle, buf, sizeof(buf))); + + nl_dump(p, "parent %s", + rtnl_tc_handle2str(tc->tc_parent, buf, sizeof(buf))); + + tc_dump(tc, NL_DUMP_LINE, p); + nl_dump(p, "\n"); +} + +void rtnl_tc_dump_details(struct nl_object *obj, struct nl_dump_params *p) +{ + struct rtnl_tc *tc = TC_CAST(obj); + + rtnl_tc_dump_line(OBJ_CAST(tc), p); + + nl_dump_line(p, " "); + + if (tc->ce_mask & TCA_ATTR_MTU) + nl_dump(p, " mtu %u", tc->tc_mtu); + + if (tc->ce_mask & TCA_ATTR_MPU) + nl_dump(p, " mpu %u", tc->tc_mpu); + + if (tc->ce_mask & TCA_ATTR_OVERHEAD) + nl_dump(p, " overhead %u", tc->tc_overhead); + + if (!tc_dump(tc, NL_DUMP_DETAILS, p)) + nl_dump(p, "no options"); + nl_dump(p, "\n"); +} + +void rtnl_tc_dump_stats(struct nl_object *obj, struct nl_dump_params *p) +{ + struct rtnl_tc *tc = TC_CAST(obj); + char *unit, fmt[64]; + float res; + + rtnl_tc_dump_details(OBJ_CAST(tc), p); + + strcpy(fmt, " %7.2f %s %10u %10u %10u %10u %10u\n"); + + nl_dump_line(p, + " Stats: bytes packets drops overlimits" \ + " qlen backlog\n"); + + res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_BYTES], &unit); + if (*unit == 'B') + fmt[11] = '9'; + + nl_dump_line(p, fmt, res, unit, + tc->tc_stats[RTNL_TC_PACKETS], + tc->tc_stats[RTNL_TC_DROPS], + tc->tc_stats[RTNL_TC_OVERLIMITS], + tc->tc_stats[RTNL_TC_QLEN], + tc->tc_stats[RTNL_TC_BACKLOG]); + + res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_RATE_BPS], &unit); + + strcpy(fmt, " %7.2f %s/s%9u pps"); + + if (*unit == 'B') + fmt[11] = '9'; + + nl_dump_line(p, fmt, res, unit, tc->tc_stats[RTNL_TC_RATE_PPS]); + + tc_dump(tc, NL_DUMP_LINE, p); + nl_dump(p, "\n"); +} + +int rtnl_tc_compare(struct nl_object *aobj, struct nl_object *bobj, + uint32_t attrs, int flags) +{ + struct rtnl_tc *a = TC_CAST(aobj); + struct rtnl_tc *b = TC_CAST(bobj); + int diff = 0; + +#define TC_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, TCA_ATTR_##ATTR, a, b, EXPR) + + diff |= TC_DIFF(HANDLE, a->tc_handle != b->tc_handle); + diff |= TC_DIFF(PARENT, a->tc_parent != b->tc_parent); + diff |= TC_DIFF(IFINDEX, a->tc_ifindex != b->tc_ifindex); + diff |= TC_DIFF(KIND, strcmp(a->tc_kind, b->tc_kind)); + +#undef TC_DIFF + + return diff; +} + +/** @} */ + +/** + * @name Modules API + */ + +struct rtnl_tc_ops *rtnl_tc_lookup_ops(enum rtnl_tc_type type, const char *kind) +{ + struct rtnl_tc_ops *ops; + + nl_list_for_each_entry(ops, &tc_ops_list[type], to_list) + if (!strcmp(kind, ops->to_kind)) + return ops; + + return NULL; +} + +struct rtnl_tc_ops *rtnl_tc_get_ops(struct rtnl_tc *tc) +{ + if (!tc->tc_ops) + tc->tc_ops = rtnl_tc_lookup_ops(tc->tc_type, tc->tc_kind); + + return tc->tc_ops; +} + +/** + * Register a traffic control module + * @arg ops traffic control module operations + */ +int rtnl_tc_register(struct rtnl_tc_ops *ops) +{ + static int init = 0; + + /* + * Initialiation hack, make sure list is initialized when + * the first tc module registers. Putting this in a + * separate __init would required correct ordering of init + * functions + */ + if (!init) { + int i; + + for (i = 0; i < __RTNL_TC_TYPE_MAX; i++) + nl_init_list_head(&tc_ops_list[i]); + + init = 1; + } + + if (!ops->to_kind || ops->to_type > RTNL_TC_TYPE_MAX) + BUG(); + + if (rtnl_tc_lookup_ops(ops->to_type, ops->to_kind)) + return -NLE_EXIST; + + nl_list_add_tail(&ops->to_list, &tc_ops_list[ops->to_type]); + + return 0; +} + +/** + * Unregister a traffic control module + * @arg ops traffic control module operations + */ +void rtnl_tc_unregister(struct rtnl_tc_ops *ops) +{ + nl_list_del(&ops->to_list); +} + +/** + * Return pointer to private data of traffic control object + * @arg tc traffic control object + * + * Allocates the private traffic control object data section + * as necessary and returns it. + * + * @return Pointer to private tc data or NULL if allocation failed. + */ +void *rtnl_tc_data(struct rtnl_tc *tc) +{ + if (!tc->tc_subdata) { + size_t size; + + if (!tc->tc_ops) { + if (!tc->tc_kind) + BUG(); + + if (!rtnl_tc_get_ops(tc)) + return NULL; + } + + if (!(size = tc->tc_ops->to_size)) + BUG(); + + if (!(tc->tc_subdata = nl_data_alloc(NULL, size))) + return NULL; + } + + return nl_data_get(tc->tc_subdata); +} + +/** + * Check traffic control object type and return private data section + * @arg tc traffic control object + * @arg ops expected traffic control object operations + * + * Checks whether the traffic control object matches the type + * specified with the traffic control object operations. If the + * type matches, the private tc object data is returned. If type + * mismatches, APPBUG() will print a application bug warning. + * + * @see rtnl_tc_data() + * + * @return Pointer to private tc data or NULL if type mismatches. + */ +void *rtnl_tc_data_check(struct rtnl_tc *tc, struct rtnl_tc_ops *ops) +{ + if (tc->tc_ops != ops) { + char buf[64]; + + snprintf(buf, sizeof(buf), + "tc object %p used in %s context but is of type %s", + tc, ops->to_kind, tc->tc_ops->to_kind); + APPBUG(buf); + + return NULL; + } + + return rtnl_tc_data(tc); +} + +void rtnl_tc_type_register(struct rtnl_tc_type_ops *ops) +{ + if (ops->tt_type > RTNL_TC_TYPE_MAX) + BUG(); + + tc_type_ops[ops->tt_type] = ops; +} + +void rtnl_tc_type_unregister(struct rtnl_tc_type_ops *ops) +{ + if (ops->tt_type > RTNL_TC_TYPE_MAX) + BUG(); + + tc_type_ops[ops->tt_type] = NULL; +} + +/** @} */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/socket.c b/libnetwork/libnl3/lib/socket.c new file mode 100644 index 0000000..01b9872 --- /dev/null +++ b/libnetwork/libnl3/lib/socket.c @@ -0,0 +1,628 @@ +/* + * lib/socket.c Netlink Socket + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup core + * @defgroup socket Socket + * @{ + */ + +#include + +#include +#include +#include +#include +#include +#include + +static int default_cb = NL_CB_DEFAULT; + +static void __init init_default_cb(void) +{ + char *nlcb; + + if ((nlcb = getenv("NLCB"))) { + if (!strcasecmp(nlcb, "default")) + default_cb = NL_CB_DEFAULT; + else if (!strcasecmp(nlcb, "verbose")) + default_cb = NL_CB_VERBOSE; + else if (!strcasecmp(nlcb, "debug")) + default_cb = NL_CB_DEBUG; + else { + fprintf(stderr, "Unknown value for NLCB, valid values: " + "{default | verbose | debug}\n"); + } + } +} + +static uint32_t used_ports_map[32]; +static pthread_mutex_t port_map_mutex = PTHREAD_MUTEX_INITIALIZER; + +static uint32_t generate_local_port(void) +{ + int i, n; + uint32_t pid = getpid() & 0x3FFFFF; + + pthread_mutex_lock(&port_map_mutex); + + for (i = 0; i < 32; i++) { + if (used_ports_map[i] == 0xFFFFFFFF) + continue; + + for (n = 0; n < 32; n++) { + if (1UL & (used_ports_map[i] >> n)) + continue; + + used_ports_map[i] |= (1UL << n); + n += (i * 32); + + /* PID_MAX_LIMIT is currently at 2^22, leaving 10 bit + * to, i.e. 1024 unique ports per application. */ + + pthread_mutex_unlock(&port_map_mutex); + + return pid + (n << 22); + } + } + + pthread_mutex_unlock(&port_map_mutex); + + /* Out of sockets in our own PID namespace, what to do? FIXME */ + return UINT_MAX; +} + +static void release_local_port(uint32_t port) +{ + int nr; + + if (port == UINT_MAX) + return; + + nr = port >> 22; + + pthread_mutex_lock(&port_map_mutex); + used_ports_map[nr / 32] &= ~(1 << (nr % 32)); + pthread_mutex_unlock(&port_map_mutex); +} + +/** + * @name Allocation + * @{ + */ + +static struct nl_sock *__alloc_socket(struct nl_cb *cb) +{ + struct nl_sock *sk; + + sk = calloc(1, sizeof(*sk)); + if (!sk) + return NULL; + + sk->s_fd = -1; + sk->s_cb = cb; + sk->s_local.nl_family = AF_NETLINK; + sk->s_peer.nl_family = AF_NETLINK; + sk->s_seq_expect = sk->s_seq_next = time(0); + sk->s_local.nl_pid = generate_local_port(); + if (sk->s_local.nl_pid == UINT_MAX) { + nl_socket_free(sk); + return NULL; + } + + return sk; +} + +/** + * Allocate new netlink socket + * + * @return Newly allocated netlink socket or NULL. + */ +struct nl_sock *nl_socket_alloc(void) +{ + struct nl_cb *cb; + + cb = nl_cb_alloc(default_cb); + if (!cb) + return NULL; + + return __alloc_socket(cb); +} + +/** + * Allocate new socket with custom callbacks + * @arg cb Callback handler + * + * The reference to the callback handler is taken into account + * automatically, it is released again upon calling nl_socket_free(). + * + *@return Newly allocted socket handle or NULL. + */ +struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb) +{ + if (cb == NULL) + BUG(); + + return __alloc_socket(nl_cb_get(cb)); +} + +/** + * Free a netlink socket. + * @arg sk Netlink socket. + */ +void nl_socket_free(struct nl_sock *sk) +{ + if (!sk) + return; + + if (sk->s_fd >= 0) + close(sk->s_fd); + + if (!(sk->s_flags & NL_OWN_PORT)) + release_local_port(sk->s_local.nl_pid); + + nl_cb_put(sk->s_cb); + free(sk); +} + +/** @} */ + +/** + * @name Sequence Numbers + * @{ + */ + +static int noop_seq_check(struct nl_msg *msg, void *arg) +{ + return NL_OK; +} + + +/** + * Disable sequence number checking. + * @arg sk Netlink socket. + * + * Disables checking of sequence numbers on the netlink socket This is + * required to allow messages to be processed which were not requested by + * a preceding request message, e.g. netlink events. + * + * @note This function modifies the NL_CB_SEQ_CHECK configuration in + * the callback handle associated with the socket. + */ +void nl_socket_disable_seq_check(struct nl_sock *sk) +{ + nl_cb_set(sk->s_cb, NL_CB_SEQ_CHECK, + NL_CB_CUSTOM, noop_seq_check, NULL); +} + +/** + * Use next sequence number + * @arg sk Netlink socket. + * + * Uses the next available sequence number and increases the counter + * by one for subsequent calls. + * + * @return Unique serial sequence number + */ +unsigned int nl_socket_use_seq(struct nl_sock *sk) +{ + return sk->s_seq_next++; +} + +/** + * Disable automatic request for ACK + * @arg sk Netlink socket. + * + * The default behaviour of a socket is to request an ACK for + * each message sent to allow for the caller to synchronize to + * the completion of the netlink operation. This function + * disables this behaviour and will result in requests being + * sent which will not have the NLM_F_ACK flag set automatically. + * However, it is still possible for the caller to set the + * NLM_F_ACK flag explicitely. + */ +void nl_socket_disable_auto_ack(struct nl_sock *sk) +{ + sk->s_flags |= NL_NO_AUTO_ACK; +} + +/** + * Enable automatic request for ACK (default) + * @arg sk Netlink socket. + * @see nl_socket_disable_auto_ack + */ +void nl_socket_enable_auto_ack(struct nl_sock *sk) +{ + sk->s_flags &= ~NL_NO_AUTO_ACK; +} + +/** @} */ + +/** + * @name Source Idenficiation + * @{ + */ + +uint32_t nl_socket_get_local_port(const struct nl_sock *sk) +{ + return sk->s_local.nl_pid; +} + +/** + * Set local port of socket + * @arg sk Netlink socket. + * @arg port Local port identifier + * + * Assigns a local port identifier to the socket. If port is 0 + * a unique port identifier will be generated automatically. + */ +void nl_socket_set_local_port(struct nl_sock *sk, uint32_t port) +{ + if (port == 0) { + port = generate_local_port(); + /* + * Release local port after generation of a new one to be + * able to change local port using nl_socket_set_local_port(, 0) + */ + if (!(sk->s_flags & NL_OWN_PORT)) + release_local_port(sk->s_local.nl_pid); + else + sk->s_flags &= ~NL_OWN_PORT; + } else { + if (!(sk->s_flags & NL_OWN_PORT)) + release_local_port(sk->s_local.nl_pid); + sk->s_flags |= NL_OWN_PORT; + } + + sk->s_local.nl_pid = port; +} + +/** @} */ + +/** + * @name Group Subscriptions + * @{ + */ + +/** + * Join groups + * @arg sk Netlink socket + * @arg group Group identifier + * + * Joins the specified groups using the modern socket option which + * is available since kernel version 2.6.14. It allows joining an + * almost arbitary number of groups without limitation. The list + * of groups has to be terminated by 0 (%NFNLGRP_NONE). + * + * Make sure to use the correct group definitions as the older + * bitmask definitions for nl_join_groups() are likely to still + * be present for backward compatibility reasons. + * + * @return 0 on sucess or a negative error code. + */ +int nl_socket_add_memberships(struct nl_sock *sk, int group, ...) +{ + int err; + va_list ap; + + if (sk->s_fd == -1) + return -NLE_BAD_SOCK; + + va_start(ap, group); + + while (group != 0) { + if (group < 0) + return -NLE_INVAL; + + err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, + &group, sizeof(group)); + if (err < 0) + return -nl_syserr2nlerr(errno); + + group = va_arg(ap, int); + } + + va_end(ap); + + return 0; +} + +int nl_socket_add_membership(struct nl_sock *sk, int group) +{ + return nl_socket_add_memberships(sk, group, 0); +} + +/** + * Leave groups + * @arg sk Netlink socket + * @arg group Group identifier + * + * Leaves the specified groups using the modern socket option + * which is available since kernel version 2.6.14. The list of groups + * has to terminated by 0 (%NFNLGRP_NONE). + * + * @see nl_socket_add_membership + * @return 0 on success or a negative error code. + */ +int nl_socket_drop_memberships(struct nl_sock *sk, int group, ...) +{ + int err; + va_list ap; + + if (sk->s_fd == -1) + return -NLE_BAD_SOCK; + + va_start(ap, group); + + while (group != 0) { + if (group < 0) + return -NLE_INVAL; + + err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, + &group, sizeof(group)); + if (err < 0) + return -nl_syserr2nlerr(errno); + + group = va_arg(ap, int); + } + + va_end(ap); + + return 0; +} + +int nl_socket_drop_membership(struct nl_sock *sk, int group) +{ + return nl_socket_drop_memberships(sk, group, 0); +} + + +/** + * Join multicast groups (deprecated) + * @arg sk Netlink socket. + * @arg groups Bitmask of groups to join. + * + * This function defines the old way of joining multicast group which + * has to be done prior to calling nl_connect(). It works on any kernel + * version but is very limited as only 32 groups can be joined. + */ +void nl_join_groups(struct nl_sock *sk, int groups) +{ + sk->s_local.nl_groups |= groups; +} + + +/** @} */ + +/** + * @name Peer Identfication + * @{ + */ + +uint32_t nl_socket_get_peer_port(const struct nl_sock *sk) +{ + return sk->s_peer.nl_pid; +} + +void nl_socket_set_peer_port(struct nl_sock *sk, uint32_t port) +{ + sk->s_peer.nl_pid = port; +} + +uint32_t nl_socket_get_peer_groups(const struct nl_sock *sk) +{ + return sk->s_peer.nl_groups; +} + +void nl_socket_set_peer_groups(struct nl_sock *sk, uint32_t groups) +{ + sk->s_peer.nl_groups = groups; +} + + + +/** @} */ + +/** + * @name File Descriptor + * @{ + */ + +int nl_socket_get_fd(const struct nl_sock *sk) +{ + return sk->s_fd; +} + +/** + * Set file descriptor of socket to non-blocking state + * @arg sk Netlink socket. + * + * @return 0 on success or a negative error code. + */ +int nl_socket_set_nonblocking(const struct nl_sock *sk) +{ + if (sk->s_fd == -1) + return -NLE_BAD_SOCK; + + if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0) + return -nl_syserr2nlerr(errno); + + return 0; +} + +/** + * Enable use of MSG_PEEK when reading from socket + * @arg sk Netlink socket. + */ +void nl_socket_enable_msg_peek(struct nl_sock *sk) +{ + sk->s_flags |= NL_MSG_PEEK; +} + +/** + * Disable use of MSG_PEEK when reading from socket + * @arg sk Netlink socket. + */ +void nl_socket_disable_msg_peek(struct nl_sock *sk) +{ + sk->s_flags &= ~NL_MSG_PEEK; +} + +/** @} */ + +/** + * @name Callback Handler + * @{ + */ + +struct nl_cb *nl_socket_get_cb(const struct nl_sock *sk) +{ + return nl_cb_get(sk->s_cb); +} + +void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb) +{ + nl_cb_put(sk->s_cb); + sk->s_cb = nl_cb_get(cb); +} + +/** + * Modify the callback handler associated with the socket + * @arg sk Netlink socket. + * @arg type which type callback to set + * @arg kind kind of callback + * @arg func callback function + * @arg arg argument to be passed to callback function + * + * @see nl_cb_set + */ +int nl_socket_modify_cb(struct nl_sock *sk, enum nl_cb_type type, + enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func, + void *arg) +{ + return nl_cb_set(sk->s_cb, type, kind, func, arg); +} + +/** + * Modify the error callback handler associated with the socket + * @arg sk Netlink socket. + * @arg kind kind of callback + * @arg func callback function + * @arg arg argument to be passed to callback function + * + * @see nl_cb_err + */ +int nl_socket_modify_err_cb(struct nl_sock *sk, enum nl_cb_kind kind, + nl_recvmsg_err_cb_t func, void *arg) +{ + return nl_cb_err(sk->s_cb, kind, func, arg); +} + +/** @} */ + +/** + * @name Utilities + * @{ + */ + +/** + * Set socket buffer size of netlink socket. + * @arg sk Netlink socket. + * @arg rxbuf New receive socket buffer size in bytes. + * @arg txbuf New transmit socket buffer size in bytes. + * + * Sets the socket buffer size of a netlink socket to the specified + * values \c rxbuf and \c txbuf. Providing a value of \c 0 assumes a + * good default value. + * + * @note It is not required to call this function prior to nl_connect(). + * @return 0 on sucess or a negative error code. + */ +int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf) +{ + int err; + + if (rxbuf <= 0) + rxbuf = 32768; + + if (txbuf <= 0) + txbuf = 32768; + + if (sk->s_fd == -1) + return -NLE_BAD_SOCK; + + err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, + &txbuf, sizeof(txbuf)); + if (err < 0) + return -nl_syserr2nlerr(errno); + + err = setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF, + &rxbuf, sizeof(rxbuf)); + if (err < 0) + return -nl_syserr2nlerr(errno); + + sk->s_flags |= NL_SOCK_BUFSIZE_SET; + + return 0; +} + +/** + * Enable/disable credential passing on netlink socket. + * @arg sk Netlink socket. + * @arg state New state (0 - disabled, 1 - enabled) + * + * @return 0 on success or a negative error code + */ +int nl_socket_set_passcred(struct nl_sock *sk, int state) +{ + int err; + + if (sk->s_fd == -1) + return -NLE_BAD_SOCK; + + err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED, + &state, sizeof(state)); + if (err < 0) + return -nl_syserr2nlerr(errno); + + if (state) + sk->s_flags |= NL_SOCK_PASSCRED; + else + sk->s_flags &= ~NL_SOCK_PASSCRED; + + return 0; +} + +/** + * Enable/disable receival of additional packet information + * @arg sk Netlink socket. + * @arg state New state (0 - disabled, 1 - enabled) + * + * @return 0 on success or a negative error code + */ +int nl_socket_recv_pktinfo(struct nl_sock *sk, int state) +{ + int err; + + if (sk->s_fd == -1) + return -NLE_BAD_SOCK; + + err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_PKTINFO, + &state, sizeof(state)); + if (err < 0) + return -nl_syserr2nlerr(errno); + + return 0; +} + +/** @} */ + +/** @} */ diff --git a/libnetwork/libnl3/lib/stamp-h1 b/libnetwork/libnl3/lib/stamp-h1 new file mode 100644 index 0000000..166946b --- /dev/null +++ b/libnetwork/libnl3/lib/stamp-h1 @@ -0,0 +1 @@ +timestamp for lib/defs.h diff --git a/libnetwork/libnl3/lib/utils.c b/libnetwork/libnl3/lib/utils.c new file mode 100644 index 0000000..0ec7626 --- /dev/null +++ b/libnetwork/libnl3/lib/utils.c @@ -0,0 +1,1040 @@ +/* + * lib/utils.c Utility Functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +/** + * @ingroup core + * @defgroup utils Utilities + * @{ + */ + +#include +#include +#include +#include + +/** + * Debug level + */ +int nl_debug = 0; + +struct nl_dump_params nl_debug_dp = { + .dp_type = NL_DUMP_DETAILS, +}; + +static void __init nl_debug_init(void) +{ + char *nldbg, *end; + + if ((nldbg = getenv("NLDBG"))) { + long level = strtol(nldbg, &end, 0); + if (nldbg != end) + nl_debug = level; + } + + nl_debug_dp.dp_fd = stderr; +} + +int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *)) +{ + FILE *fd; + char buf[128]; + + fd = fopen(path, "r"); + if (fd == NULL) + return -nl_syserr2nlerr(errno); + + while (fgets(buf, sizeof(buf), fd)) { + int goodlen, err; + long num; + char *end; + + if (*buf == '#' || *buf == '\n' || *buf == '\r') + continue; + + num = strtol(buf, &end, 0); + if (end == buf) + return -NLE_INVAL; + + if (num == LONG_MIN || num == LONG_MAX) + return -NLE_RANGE; + + while (*end == ' ' || *end == '\t') + end++; + + goodlen = strcspn(end, "#\r\n\t "); + if (goodlen == 0) + return -NLE_INVAL; + + end[goodlen] = '\0'; + + err = cb(num, end); + if (err < 0) + return err; + } + + fclose(fd); + + return 0; +} + +/** + * @name Unit Pretty-Printing + * @{ + */ + +/** + * Cancel down a byte counter + * @arg l byte counter + * @arg unit destination unit pointer + * + * Cancels down a byte counter until it reaches a reasonable + * unit. The chosen unit is assigned to \a unit. + * + * @return The cancelled down byte counter in the new unit. + */ +double nl_cancel_down_bytes(unsigned long long l, char **unit) +{ + if (l >= 1099511627776LL) { + *unit = "TiB"; + return ((double) l) / 1099511627776LL; + } else if (l >= 1073741824) { + *unit = "GiB"; + return ((double) l) / 1073741824; + } else if (l >= 1048576) { + *unit = "MiB"; + return ((double) l) / 1048576; + } else if (l >= 1024) { + *unit = "KiB"; + return ((double) l) / 1024; + } else { + *unit = "B"; + return (double) l; + } +} + +/** + * Cancel down a bit counter + * @arg l bit counter + * @arg unit destination unit pointer + * + * Cancels downa bit counter until it reaches a reasonable + * unit. The chosen unit is assigned to \a unit. + * + * @return The cancelled down bit counter in the new unit. + */ +double nl_cancel_down_bits(unsigned long long l, char **unit) +{ + if (l >= 1099511627776ULL) { + *unit = "Tbit"; + return ((double) l) / 1099511627776ULL; + } else if (l >= 1073741824) { + *unit = "Gbit"; + return ((double) l) / 1073741824; + } else if (l >= 1048576) { + *unit = "Mbit"; + return ((double) l) / 1048576; + } else if (l >= 1024) { + *unit = "Kbit"; + return ((double) l) / 1024; + } else { + *unit = "bit"; + return (double) l; + } + +} + +int nl_rate2str(unsigned long long rate, int type, char *buf, size_t len) +{ + char *unit; + double frac; + + switch (type) { + case NL_BYTE_RATE: + frac = nl_cancel_down_bytes(rate, &unit); + break; + + case NL_BIT_RATE: + frac = nl_cancel_down_bits(rate, &unit); + break; + + default: + BUG(); + } + + return snprintf(buf, len, "%.2f%s/s", frac, unit); +} + +/** + * Cancel down a micro second value + * @arg l micro seconds + * @arg unit destination unit pointer + * + * Cancels down a microsecond counter until it reaches a + * reasonable unit. The chosen unit is assigned to \a unit. + * + * @return The cancelled down microsecond in the new unit + */ +double nl_cancel_down_us(uint32_t l, char **unit) +{ + if (l >= 1000000) { + *unit = "s"; + return ((double) l) / 1000000; + } else if (l >= 1000) { + *unit = "ms"; + return ((double) l) / 1000; + } else { + *unit = "us"; + return (double) l; + } +} + +/** @} */ + +/** + * @name Generic Unit Translations + * @{ + */ + +/** + * Convert a character string to a size + * @arg str size encoded as character string + * + * Converts the specified size as character to the corresponding + * number of bytes. + * + * Supported formats are: + * - b,kb/k,m/mb,gb/g for bytes + * - bit,kbit/mbit/gbit + * + * @return The number of bytes or -1 if the string is unparseable + */ +long nl_size2int(const char *str) +{ + char *p; + long l = strtol(str, &p, 0); + if (p == str) + return -NLE_INVAL; + + if (*p) { + if (!strcasecmp(p, "kb") || !strcasecmp(p, "k")) + l *= 1024; + else if (!strcasecmp(p, "gb") || !strcasecmp(p, "g")) + l *= 1024*1024*1024; + else if (!strcasecmp(p, "gbit")) + l *= 1024*1024*1024/8; + else if (!strcasecmp(p, "mb") || !strcasecmp(p, "m")) + l *= 1024*1024; + else if (!strcasecmp(p, "mbit")) + l *= 1024*1024/8; + else if (!strcasecmp(p, "kbit")) + l *= 1024/8; + else if (!strcasecmp(p, "bit")) + l /= 8; + else if (strcasecmp(p, "b") != 0) + return -NLE_INVAL; + } + + return l; +} + +static const struct { + double limit; + const char *unit; +} size_units[] = { + { 1024. * 1024. * 1024. * 1024. * 1024., "EiB" }, + { 1024. * 1024. * 1024. * 1024., "TiB" }, + { 1024. * 1024. * 1024., "GiB" }, + { 1024. * 1024., "MiB" }, + { 1024., "KiB" }, + { 0., "B" }, +}; + +/** + * Convert a size toa character string + * @arg size Size in number of bytes + * @arg buf Buffer to write character string to + * @arg len Size of buf + * + * This function converts a value in bytes to a human readable representation + * of it. The function uses IEC prefixes: + * + * @code + * 1024 bytes => 1 KiB + * 1048576 bytes => 1 MiB + * @endcode + * + * The highest prefix is used which ensures a result of >= 1.0, the result + * is provided as floating point number with a maximum precision of 2 digits: + * @code + * 965176 bytes => 942.55 KiB + * @endcode + * + * @return pointer to buf + */ +char *nl_size2str(const size_t size, char *buf, const size_t len) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(size_units); i++) { + if (size >= size_units[i].limit) { + snprintf(buf, len, "%.2g%s", + (double) size / size_units[i].limit, + size_units[i].unit); + return buf; + } + } + + BUG(); +} + +/** + * Convert a character string to a probability + * @arg str probability encoded as character string + * + * Converts the specified probability as character to the + * corresponding probability number. + * + * Supported formats are: + * - 0.0-1.0 + * - 0%-100% + * + * @return The probability relative to NL_PROB_MIN and NL_PROB_MAX + */ +long nl_prob2int(const char *str) +{ + char *p; + double d = strtod(str, &p); + + if (p == str) + return -NLE_INVAL; + + if (d > 1.0) + d /= 100.0f; + + if (d > 1.0f || d < 0.0f) + return -NLE_RANGE; + + if (*p && strcmp(p, "%") != 0) + return -NLE_INVAL; + + return rint(d * NL_PROB_MAX); +} + +/** @} */ + +/** + * @name Time Translations + * @{ + */ + +#ifdef USER_HZ +static uint32_t user_hz = USER_HZ; +#else +static uint32_t user_hz = 100; +#endif + +static double ticks_per_usec = 1.0f; + +/* Retrieves the configured HZ and ticks/us value in the kernel. + * The value is cached. Supported ways of getting it: + * + * 1) environment variable + * 2) /proc/net/psched and sysconf + * + * Supports the environment variables: + * PROC_NET_PSCHED - may point to psched file in /proc + * PROC_ROOT - may point to /proc fs */ +static void __init get_psched_settings(void) +{ + char name[FILENAME_MAX]; + FILE *fd; + int got_hz = 0; + + if (getenv("HZ")) { + long hz = strtol(getenv("HZ"), NULL, 0); + + if (LONG_MIN != hz && LONG_MAX != hz) { + user_hz = hz; + got_hz = 1; + } + } + + if (!got_hz) + user_hz = sysconf(_SC_CLK_TCK); + + if (getenv("TICKS_PER_USEC")) { + double t = strtod(getenv("TICKS_PER_USEC"), NULL); + ticks_per_usec = t; + } + else { + if (getenv("PROC_NET_PSCHED")) + snprintf(name, sizeof(name), "%s", getenv("PROC_NET_PSCHED")); + else if (getenv("PROC_ROOT")) + snprintf(name, sizeof(name), "%s/net/psched", + getenv("PROC_ROOT")); + else + strncpy(name, "/proc/net/psched", sizeof(name) - 1); + + if ((fd = fopen(name, "r"))) { + uint32_t ns_per_usec, ns_per_tick; + /* the file contains 4 hexadecimals, but we just use + the first two of them */ + fscanf(fd, "%08x %08x", &ns_per_usec, &ns_per_tick); + + ticks_per_usec = (double) ns_per_usec / + (double) ns_per_tick; + + + fclose(fd); + } + } +} + + +/** + * Return the value of HZ + */ +int nl_get_user_hz(void) +{ + return user_hz; +} + + +/** + * Convert micro seconds to ticks + * @arg us micro seconds + * @return number of ticks + */ +uint32_t nl_us2ticks(uint32_t us) +{ + return us * ticks_per_usec; +} + + +/** + * Convert ticks to micro seconds + * @arg ticks number of ticks + * @return microseconds + */ +uint32_t nl_ticks2us(uint32_t ticks) +{ + return ticks / ticks_per_usec; +} + +int nl_str2msec(const char *str, uint64_t *result) +{ + uint64_t total = 0, l; + int plen; + char *p; + + do { + l = strtoul(str, &p, 0); + if (p == str) + return -NLE_INVAL; + else if (*p) { + plen = strcspn(p, " \t"); + + if (!plen) + total += l; + else if (!strncasecmp(p, "sec", plen)) + total += (l * 1000); + else if (!strncasecmp(p, "min", plen)) + total += (l * 1000*60); + else if (!strncasecmp(p, "hour", plen)) + total += (l * 1000*60*60); + else if (!strncasecmp(p, "day", plen)) + total += (l * 1000*60*60*24); + else + return -NLE_INVAL; + + str = p + plen; + } else + total += l; + } while (*str && *p); + + *result = total; + + return 0; +} + +/** + * Convert milliseconds to a character string + * @arg msec number of milliseconds + * @arg buf destination buffer + * @arg len buffer length + * + * Converts milliseconds to a character string split up in days, hours, + * minutes, seconds, and milliseconds and stores it in the specified + * destination buffer. + * + * @return The destination buffer. + */ +char * nl_msec2str(uint64_t msec, char *buf, size_t len) +{ + int i, split[5]; + char *units[] = {"d", "h", "m", "s", "msec"}; + +#define _SPLIT(idx, unit) if ((split[idx] = msec / unit) > 0) msec %= unit + _SPLIT(0, 86400000); /* days */ + _SPLIT(1, 3600000); /* hours */ + _SPLIT(2, 60000); /* minutes */ + _SPLIT(3, 1000); /* seconds */ +#undef _SPLIT + split[4] = msec; + + memset(buf, 0, len); + + for (i = 0; i < ARRAY_SIZE(split); i++) { + if (split[i] > 0) { + char t[64]; + snprintf(t, sizeof(t), "%s%d%s", + strlen(buf) ? " " : "", split[i], units[i]); + strncat(buf, t, len - strlen(buf) - 1); + } + } + + return buf; +} + +/** @} */ + +/** + * @name Netlink Family Translations + * @{ + */ + +static const struct trans_tbl nlfamilies[] = { + __ADD(NETLINK_ROUTE,route) + __ADD(NETLINK_USERSOCK,usersock) + __ADD(NETLINK_FIREWALL,firewall) + __ADD(NETLINK_INET_DIAG,inetdiag) + __ADD(NETLINK_NFLOG,nflog) + __ADD(NETLINK_XFRM,xfrm) + __ADD(NETLINK_SELINUX,selinux) + __ADD(NETLINK_ISCSI,iscsi) + __ADD(NETLINK_AUDIT,audit) + __ADD(NETLINK_FIB_LOOKUP,fib_lookup) + __ADD(NETLINK_CONNECTOR,connector) + __ADD(NETLINK_NETFILTER,netfilter) + __ADD(NETLINK_IP6_FW,ip6_fw) + __ADD(NETLINK_DNRTMSG,dnrtmsg) + __ADD(NETLINK_KOBJECT_UEVENT,kobject_uevent) + __ADD(NETLINK_GENERIC,generic) + __ADD(NETLINK_SCSITRANSPORT,scsitransport) + __ADD(NETLINK_ECRYPTFS,ecryptfs) +}; + +char * nl_nlfamily2str(int family, char *buf, size_t size) +{ + return __type2str(family, buf, size, nlfamilies, + ARRAY_SIZE(nlfamilies)); +} + +int nl_str2nlfamily(const char *name) +{ + return __str2type(name, nlfamilies, ARRAY_SIZE(nlfamilies)); +} + +/** + * @} + */ + +/** + * @name Link Layer Protocol Translations + * @{ + */ + +static const struct trans_tbl llprotos[] = { + {0, "generic"}, + __ADD(ARPHRD_ETHER,ether) + __ADD(ARPHRD_EETHER,eether) + __ADD(ARPHRD_AX25,ax25) + __ADD(ARPHRD_PRONET,pronet) + __ADD(ARPHRD_CHAOS,chaos) + __ADD(ARPHRD_IEEE802,ieee802) + __ADD(ARPHRD_ARCNET,arcnet) + __ADD(ARPHRD_APPLETLK,atalk) + __ADD(ARPHRD_DLCI,dlci) + __ADD(ARPHRD_ATM,atm) + __ADD(ARPHRD_METRICOM,metricom) + __ADD(ARPHRD_IEEE1394,ieee1394) +#ifdef ARPHRD_EUI64 + __ADD(ARPHRD_EUI64,eui64) +#endif + __ADD(ARPHRD_INFINIBAND,infiniband) + __ADD(ARPHRD_SLIP,slip) + __ADD(ARPHRD_CSLIP,cslip) + __ADD(ARPHRD_SLIP6,slip6) + __ADD(ARPHRD_CSLIP6,cslip6) + __ADD(ARPHRD_RSRVD,rsrvd) + __ADD(ARPHRD_ADAPT,adapt) + __ADD(ARPHRD_ROSE,rose) + __ADD(ARPHRD_X25,x25) +#ifdef ARPHRD_HWX25 + __ADD(ARPHRD_HWX25,hwx25) +#endif + __ADD(ARPHRD_CAN,can) + __ADD(ARPHRD_PPP,ppp) + __ADD(ARPHRD_HDLC,hdlc) + __ADD(ARPHRD_LAPB,lapb) + __ADD(ARPHRD_DDCMP,ddcmp) + __ADD(ARPHRD_RAWHDLC,rawhdlc) + __ADD(ARPHRD_TUNNEL,ipip) + __ADD(ARPHRD_TUNNEL6,tunnel6) + __ADD(ARPHRD_FRAD,frad) + __ADD(ARPHRD_SKIP,skip) + __ADD(ARPHRD_LOOPBACK,loopback) + __ADD(ARPHRD_LOCALTLK,localtlk) + __ADD(ARPHRD_FDDI,fddi) + __ADD(ARPHRD_BIF,bif) + __ADD(ARPHRD_SIT,sit) + __ADD(ARPHRD_IPDDP,ip/ddp) + __ADD(ARPHRD_IPGRE,gre) + __ADD(ARPHRD_PIMREG,pimreg) + __ADD(ARPHRD_HIPPI,hippi) + __ADD(ARPHRD_ASH,ash) + __ADD(ARPHRD_ECONET,econet) + __ADD(ARPHRD_IRDA,irda) + __ADD(ARPHRD_FCPP,fcpp) + __ADD(ARPHRD_FCAL,fcal) + __ADD(ARPHRD_FCPL,fcpl) + __ADD(ARPHRD_FCFABRIC,fcfb_0) + __ADD(ARPHRD_FCFABRIC+1,fcfb_1) + __ADD(ARPHRD_FCFABRIC+2,fcfb_2) + __ADD(ARPHRD_FCFABRIC+3,fcfb_3) + __ADD(ARPHRD_FCFABRIC+4,fcfb_4) + __ADD(ARPHRD_FCFABRIC+5,fcfb_5) + __ADD(ARPHRD_FCFABRIC+6,fcfb_6) + __ADD(ARPHRD_FCFABRIC+7,fcfb_7) + __ADD(ARPHRD_FCFABRIC+8,fcfb_8) + __ADD(ARPHRD_FCFABRIC+9,fcfb_9) + __ADD(ARPHRD_FCFABRIC+10,fcfb_10) + __ADD(ARPHRD_FCFABRIC+11,fcfb_11) + __ADD(ARPHRD_FCFABRIC+12,fcfb_12) + __ADD(ARPHRD_IEEE802_TR,tr) + __ADD(ARPHRD_IEEE80211,ieee802.11) + __ADD(ARPHRD_PHONET,phonet) + __ADD(ARPHRD_CAIF, caif) +#ifdef ARPHRD_IEEE80211_PRISM + __ADD(ARPHRD_IEEE80211_PRISM, ieee802.11_prism) +#endif +#ifdef ARPHRD_VOID + __ADD(ARPHRD_VOID,void) +#endif +#ifdef ARPHRD_NONE + __ADD(ARPHRD_NONE,nohdr) +#endif +}; + +char * nl_llproto2str(int llproto, char *buf, size_t len) +{ + return __type2str(llproto, buf, len, llprotos, ARRAY_SIZE(llprotos)); +} + +int nl_str2llproto(const char *name) +{ + return __str2type(name, llprotos, ARRAY_SIZE(llprotos)); +} + +/** @} */ + + +/** + * @name Ethernet Protocol Translations + * @{ + */ + +static const struct trans_tbl ether_protos[] = { + __ADD(ETH_P_LOOP,loop) + __ADD(ETH_P_PUP,pup) + __ADD(ETH_P_PUPAT,pupat) + __ADD(ETH_P_IP,ip) + __ADD(ETH_P_X25,x25) + __ADD(ETH_P_ARP,arp) + __ADD(ETH_P_BPQ,bpq) + __ADD(ETH_P_IEEEPUP,ieeepup) + __ADD(ETH_P_IEEEPUPAT,ieeepupat) + __ADD(ETH_P_DEC,dec) + __ADD(ETH_P_DNA_DL,dna_dl) + __ADD(ETH_P_DNA_RC,dna_rc) + __ADD(ETH_P_DNA_RT,dna_rt) + __ADD(ETH_P_LAT,lat) + __ADD(ETH_P_DIAG,diag) + __ADD(ETH_P_CUST,cust) + __ADD(ETH_P_SCA,sca) + __ADD(ETH_P_TEB,teb) + __ADD(ETH_P_RARP,rarp) + __ADD(ETH_P_ATALK,atalk) + __ADD(ETH_P_AARP,aarp) +#ifdef ETH_P_8021Q + __ADD(ETH_P_8021Q,802.1q) +#endif + __ADD(ETH_P_IPX,ipx) + __ADD(ETH_P_IPV6,ipv6) + __ADD(ETH_P_PAUSE,pause) + __ADD(ETH_P_SLOW,slow) +#ifdef ETH_P_WCCP + __ADD(ETH_P_WCCP,wccp) +#endif + __ADD(ETH_P_PPP_DISC,ppp_disc) + __ADD(ETH_P_PPP_SES,ppp_ses) + __ADD(ETH_P_MPLS_UC,mpls_uc) + __ADD(ETH_P_MPLS_MC,mpls_mc) + __ADD(ETH_P_ATMMPOA,atmmpoa) + __ADD(ETH_P_LINK_CTL,link_ctl) + __ADD(ETH_P_ATMFATE,atmfate) + __ADD(ETH_P_PAE,pae) + __ADD(ETH_P_AOE,aoe) + __ADD(ETH_P_TIPC,tipc) + __ADD(ETH_P_1588,ieee1588) + __ADD(ETH_P_FCOE,fcoe) + __ADD(ETH_P_FIP,fip) + __ADD(ETH_P_EDSA,edsa) + __ADD(ETH_P_EDP2,edp2) + __ADD(ETH_P_802_3,802.3) + __ADD(ETH_P_AX25,ax25) + __ADD(ETH_P_ALL,all) + __ADD(ETH_P_802_2,802.2) + __ADD(ETH_P_SNAP,snap) + __ADD(ETH_P_DDCMP,ddcmp) + __ADD(ETH_P_WAN_PPP,wan_ppp) + __ADD(ETH_P_PPP_MP,ppp_mp) + __ADD(ETH_P_LOCALTALK,localtalk) + __ADD(ETH_P_CAN,can) + __ADD(ETH_P_PPPTALK,ppptalk) + __ADD(ETH_P_TR_802_2,tr_802.2) + __ADD(ETH_P_MOBITEX,mobitex) + __ADD(ETH_P_CONTROL,control) + __ADD(ETH_P_IRDA,irda) + __ADD(ETH_P_ECONET,econet) + __ADD(ETH_P_HDLC,hdlc) + __ADD(ETH_P_ARCNET,arcnet) + __ADD(ETH_P_DSA,dsa) + __ADD(ETH_P_TRAILER,trailer) + __ADD(ETH_P_PHONET,phonet) + __ADD(ETH_P_IEEE802154,ieee802154) + __ADD(ETH_P_CAIF,caif) +}; + +char *nl_ether_proto2str(int eproto, char *buf, size_t len) +{ + return __type2str(eproto, buf, len, ether_protos, + ARRAY_SIZE(ether_protos)); +} + +int nl_str2ether_proto(const char *name) +{ + return __str2type(name, ether_protos, ARRAY_SIZE(ether_protos)); +} + +/** @} */ + +/** + * @name IP Protocol Translations + * @{ + */ + +char *nl_ip_proto2str(int proto, char *buf, size_t len) +{ + struct protoent *p = getprotobynumber(proto); + + if (p) { + snprintf(buf, len, "%s", p->p_name); + return buf; + } + + snprintf(buf, len, "0x%x", proto); + return buf; +} + +int nl_str2ip_proto(const char *name) +{ + struct protoent *p = getprotobyname(name); + unsigned long l; + char *end; + + if (p) + return p->p_proto; + + l = strtoul(name, &end, 0); + if (l == ULONG_MAX || *end != '\0') + return -NLE_OBJ_NOTFOUND; + + return (int) l; +} + +/** @} */ + +/** + * @name Dumping Helpers + * @{ + */ + +/** + * Handle a new line while dumping + * @arg params Dumping parameters + * + * This function must be called before dumping any onto a + * new line. It will ensure proper prefixing as specified + * by the dumping parameters. + * + * @note This function will NOT dump any newlines itself + */ +void nl_new_line(struct nl_dump_params *params) +{ + params->dp_line++; + + if (params->dp_prefix) { + int i; + for (i = 0; i < params->dp_prefix; i++) { + if (params->dp_fd) + fprintf(params->dp_fd, " "); + else if (params->dp_buf) + strncat(params->dp_buf, " ", + params->dp_buflen - + sizeof(params->dp_buf) - 1); + } + } + + if (params->dp_nl_cb) + params->dp_nl_cb(params, params->dp_line); +} + +static void dump_one(struct nl_dump_params *parms, const char *fmt, + va_list args) +{ + if (parms->dp_fd) + vfprintf(parms->dp_fd, fmt, args); + else if (parms->dp_buf || parms->dp_cb) { + char *buf = NULL; + if (vasprintf(&buf, fmt, args) >= 0) { + if (parms->dp_cb) + parms->dp_cb(parms, buf); + else + strncat(parms->dp_buf, buf, + parms->dp_buflen - strlen(parms->dp_buf) - 1); + free(buf); + } + } +} + + +/** + * Dump a formatted character string + * @arg params Dumping parameters + * @arg fmt printf style formatting string + * @arg ... Arguments to formatting string + * + * Dumps a printf style formatting string to the output device + * as specified by the dumping parameters. + */ +void nl_dump(struct nl_dump_params *params, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + dump_one(params, fmt, args); + va_end(args); +} + +void nl_dump_line(struct nl_dump_params *parms, const char *fmt, ...) +{ + va_list args; + + nl_new_line(parms); + + va_start(args, fmt); + dump_one(parms, fmt, args); + va_end(args); +} + + +/** @} */ + +/** @cond SKIP */ + +int __trans_list_add(int i, const char *a, struct nl_list_head *head) +{ + struct trans_list *tl; + + tl = calloc(1, sizeof(*tl)); + if (!tl) + return -NLE_NOMEM; + + tl->i = i; + tl->a = strdup(a); + + nl_list_add_tail(&tl->list, head); + + return 0; +} + +void __trans_list_clear(struct nl_list_head *head) +{ + struct trans_list *tl, *next; + + nl_list_for_each_entry_safe(tl, next, head, list) { + free(tl->a); + free(tl); + } + + nl_init_list_head(head); +} + +char *__type2str(int type, char *buf, size_t len, + const struct trans_tbl *tbl, size_t tbl_len) +{ + int i; + for (i = 0; i < tbl_len; i++) { + if (tbl[i].i == type) { + snprintf(buf, len, "%s", tbl[i].a); + return buf; + } + } + + snprintf(buf, len, "0x%x", type); + return buf; +} + +char *__list_type2str(int type, char *buf, size_t len, + struct nl_list_head *head) +{ + struct trans_list *tl; + + nl_list_for_each_entry(tl, head, list) { + if (tl->i == type) { + snprintf(buf, len, "%s", tl->a); + return buf; + } + } + + snprintf(buf, len, "0x%x", type); + return buf; +} + +char *__flags2str(int flags, char *buf, size_t len, + const struct trans_tbl *tbl, size_t tbl_len) +{ + int i; + int tmp = flags; + + memset(buf, 0, len); + + for (i = 0; i < tbl_len; i++) { + if (tbl[i].i & tmp) { + tmp &= ~tbl[i].i; + strncat(buf, tbl[i].a, len - strlen(buf) - 1); + if ((tmp & flags)) + strncat(buf, ",", len - strlen(buf) - 1); + } + } + + return buf; +} + +int __str2type(const char *buf, const struct trans_tbl *tbl, size_t tbl_len) +{ + unsigned long l; + char *end; + int i; + + if (*buf == '\0') + return -NLE_INVAL; + + for (i = 0; i < tbl_len; i++) + if (!strcasecmp(tbl[i].a, buf)) + return tbl[i].i; + + l = strtoul(buf, &end, 0); + if (l == ULONG_MAX || *end != '\0') + return -NLE_OBJ_NOTFOUND; + + return (int) l; +} + +int __list_str2type(const char *buf, struct nl_list_head *head) +{ + struct trans_list *tl; + unsigned long l; + char *end; + + if (*buf == '\0') + return -NLE_INVAL; + + nl_list_for_each_entry(tl, head, list) { + if (!strcasecmp(tl->a, buf)) + return tl->i; + } + + l = strtoul(buf, &end, 0); + if (l == ULONG_MAX || *end != '\0') + return -NLE_OBJ_NOTFOUND; + + return (int) l; +} + +int __str2flags(const char *buf, const struct trans_tbl *tbl, size_t tbl_len) +{ + int i, flags = 0, len; + char *p = (char *) buf, *t; + + for (;;) { + if (*p == ' ') + p++; + + t = strchr(p, ','); + len = t ? t - p : strlen(p); + for (i = 0; i < tbl_len; i++) + if (!strncasecmp(tbl[i].a, p, len)) + flags |= tbl[i].i; + + if (!t) + return flags; + + p = ++t; + } + + return 0; +} + +void dump_from_ops(struct nl_object *obj, struct nl_dump_params *params) +{ + int type = params->dp_type; + + if (type < 0 || type > NL_DUMP_MAX) + BUG(); + + params->dp_line = 0; + + if (params->dp_dump_msgtype) { +#if 0 + /* XXX */ + char buf[64]; + + dp_dump_line(params, 0, "%s ", + nl_cache_mngt_type2name(obj->ce_ops, + obj->ce_ops->co_protocol, + obj->ce_msgtype, + buf, sizeof(buf))); +#endif + params->dp_pre_dump = 1; + } + + if (params->dp_buf) + memset(params->dp_buf, 0, params->dp_buflen); + + if (obj->ce_ops->oo_dump[type]) + obj->ce_ops->oo_dump[type](obj, params); +} + +/** @endcond */ + +/** @} */ -- 1.7.6 From cvincent at linux.vnet.ibm.com Thu Jan 12 14:02:16 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Thu, 12 Jan 2012 09:02:16 -0500 Subject: [Libvirt-cim] [PATCH 1/2] VirtualSystemManagementService: Remove dead code In-Reply-To: <4EFDE389.1040501@linux.vnet.ibm.com> References: <1325181355-20808-1-git-send-email-eblima@linux.vnet.ibm.com> <1325181355-20808-2-git-send-email-eblima@linux.vnet.ibm.com> <4EFDE389.1040501@linux.vnet.ibm.com> Message-ID: <4F0EE7E8.6010001@linux.vnet.ibm.com> Pushed. On 12/30/2011 11:15 AM, Chip Vincent wrote: > +1. Thanks. > > On 12/29/2011 12:55 PM, Eduardo Lima (Etrunko) wrote: >> From: Eduardo Lima (Etrunko) >> >> Signed-off-by: Eduardo Lima (Etrunko) >> --- >> src/Virt_VirtualSystemManagementService.c | 64 ----------------------------- >> 1 files changed, 0 insertions(+), 64 deletions(-) >> >> diff --git a/src/Virt_VirtualSystemManagementService.c >> b/src/Virt_VirtualSystemManagementService.c >> index 0141515..4d26429 100644 >> --- a/src/Virt_VirtualSystemManagementService.c >> +++ b/src/Virt_VirtualSystemManagementService.c >> @@ -768,70 +768,6 @@ static const char *_net_rand_mac(const CMPIObjectPath *ref) >> return _mac; >> } >> >> -/* >> -static const char *filter_by_address(struct inst_list *src, >> - const char *address) >> -{ >> - int i; >> - CMPIrc ret; >> - const char *addr; >> - const char *msg = NULL; >> - CMPIInstance *inst; >> - >> - for (i = 0; i< src->cur; i++) { >> - inst = src->list[i]; >> - ret = cu_get_str_prop(inst, "Address",&addr); >> - >> - if (ret != CMPI_RC_OK) >> - continue; >> - >> - if (STREQ(addr, address)) { >> - msg = "Conflicting MAC Addresses"; >> - goto out; >> - } >> - } >> -out: >> - return msg; >> - >> -} >> - >> -static const char *check_duplicate_mac(CMPIInstance *inst, >> - const char *mac, >> - const char *ns) >> -{ >> - CMPIObjectPath *op = NULL; >> - CMPIStatus s; >> - const char *msg = NULL; >> - const char *props[] = {"Address", NULL}; >> - struct inst_list in_list; >> - >> - op = CMGetObjectPath(inst,&s); >> - if ((op == NULL) || (s.rc != CMPI_RC_OK)) { >> - msg = "Unable to get a reference to the guest"; >> - goto out; >> - } >> - >> - FIXME: This is a Pegasus work around. Pegsus loses the namespace >> - when an ObjectPath is pulled from an instance >> - >> - if (STREQ(NAMESPACE(op), "")) >> - CMSetNameSpace(op, ns); >> - >> - inst_list_init(&in_list); >> - s = enum_rasds(_BROKER, op, NULL, CIM_RES_TYPE_NET, props,&in_list); >> - if (s.rc != CMPI_RC_OK) { >> - msg = "Failed to enumerate network instances"; >> - goto out; >> - } >> - >> - msg = filter_by_address(&in_list, mac); >> - >> -out: >> - inst_list_free(&in_list); >> - return msg; >> -} >> -*/ >> - >> static const char *net_rasd_to_vdev(CMPIInstance *inst, >> struct virt_device *dev, >> const char *ns) > > -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From cvincent at linux.vnet.ibm.com Thu Jan 12 14:01:51 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Thu, 12 Jan 2012 09:01:51 -0500 Subject: [Libvirt-cim] [PATCHv2] Remove compilation warnings In-Reply-To: <1326217662-8281-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326217662-8281-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F0EE7CF.8060309@linux.vnet.ibm.com> No issues on RHEL 6.2. +1 and pushed. Thanks. On 01/10/2012 12:47 PM, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > I am building libvirt-cim with gcc 4.6.3 in fedora 16 and got a bunch of new > warnings. Most of them are about variables that are set but not used anywhere, > but there is one possible access to unitialized variables in Virt_RASD.c which > might result in unexpected behavior. > > xmlgen.c: In function 'system_xml': > xmlgen.c:633:28: error: variable 'bl' set but not used [-Werror=unused-but-set-variable] > xmlgen.c:642:28: error: variable 'bl_args' set but not used [-Werror=unused-but-set-variable] > xmlgen.c: In function 'disk_pool_xml': > xmlgen.c:1244:20: error: variable 'path' set but not used [-Werror=unused-but-set-variable] > xmlgen.c: In function 'filter_to_xml': > xmlgen.c:1474:15: error: variable 'msg' set but not used [-Werror=unused-but-set-variable] > > Virt_FilterEntry.c: In function 'enum_filter_rules': > Virt_FilterEntry.c:576:30: error: variable 'class_type' set but not used [-Werror=unused-but-set-variable] > > Virt_RASD.c: In function 'rasd_from_vdev': > Virt_RASD.c:406:27: error: 'pool' may be used uninitialized in this function [-Werror=uninitialized] > Virt_RASD.c:330:27: note: 'pool' was declared here > Virt_RASD.c:407:26: error: 'vol' may be used uninitialized in this function [-Werror=uninitialized] > Virt_RASD.c:320:26: note: 'vol' was declared here > > Virt_VSMigrationService.c: In function 'clear_infstore_migration_flag': > Virt_VSMigrationService.c:1185:15: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] > Virt_VSMigrationService.c: In function 'migrate_do': > Virt_VSMigrationService.c:1478:15: error: variable 'thread' set but not used [-Werror=unused-but-set-variable] > > Virt_Device.c: In function 'device_instances': > Virt_Device.c:431:15: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] > Virt_Device.c: In function 'proc_dev_list': > Virt_Device.c:657:13: error: variable 'rc' set but not used [-Werror=unused-but-set-variable] > Virt_Device.c: In function 'get_device_by_name': > Virt_Device.c:769:21: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] > Virt_Device.c:729:15: error: variable 'rc' set but not used [-Werror=unused-but-set-variable] > > Virt_VirtualSystemManagementService.c: In function 'input_rasd_to_vdev': > Virt_VirtualSystemManagementService.c:1384:21: error: variable 'msg' set but not used [-Werror=unused-but-set-variable] > > Changes since v1: > - xmlgen.c: Keep 'path' variable and fix value check. > > Signed-off-by: Eduardo Lima (Etrunko) > --- > libxkutil/xmlgen.c | 33 ++++++----------------- > src/Virt_Device.c | 39 +++++++++-------------------- > src/Virt_FilterEntry.c | 11 ++------ > src/Virt_RASD.c | 17 +++++++----- > src/Virt_VSMigrationService.c | 6 +--- > src/Virt_VirtualSystemManagementService.c | 5 +-- > 6 files changed, 38 insertions(+), 73 deletions(-) > > diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c > index afd8c21..d73ffd0 100644 > --- a/libxkutil/xmlgen.c > +++ b/libxkutil/xmlgen.c > @@ -630,21 +630,17 @@ static char *system_xml(xmlNodePtr root, struct domain *domain) > tmp = xmlNewChild(root, NULL, BAD_CAST "name", BAD_CAST domain->name); > > if (domain->bootloader) { > - xmlNodePtr bl; > - > - bl = xmlNewChild(root, > - NULL, > - BAD_CAST "bootloader", > - BAD_CAST domain->bootloader); > + tmp = xmlNewChild(root, > + NULL, > + BAD_CAST "bootloader", > + BAD_CAST domain->bootloader); > } > > if (domain->bootloader_args) { > - xmlNodePtr bl_args; > - > - bl_args = xmlNewChild(root, > - NULL, > - BAD_CAST "bootloader_args", > - BAD_CAST domain->bootloader_args); > + tmp = xmlNewChild(root, > + NULL, > + BAD_CAST "bootloader_args", > + BAD_CAST domain->bootloader_args); > } > > tmp = xmlNewChild(root, > @@ -1272,7 +1268,7 @@ static const char *disk_pool_xml(xmlNodePtr root, > goto out; > > path = xmlNewChild(target, NULL, BAD_CAST "path", BAD_CAST pool->path); > - if (target == NULL) > + if (path == NULL) > goto out; > > return NULL; > @@ -1471,7 +1467,6 @@ char *res_to_xml(struct virt_pool_res *res) { > > char *filter_to_xml(struct acl_filter *filter) > { > - char *msg = XML_ERROR; > char *xml = NULL; > xmlNodePtr root = NULL; > xmlNodePtr tmp = NULL; > @@ -1504,17 +1499,7 @@ char *filter_to_xml(struct acl_filter *filter) > goto out; > } > > - /* TODO: Not yet supported > - for (i = 0; i< filter->rule_ct; i++) { > - msg = rule_to_xml(root, filter->rules[i]); > - if (msg != NULL) > - goto out; > - } > - */ > - > xml = tree_to_xml(root); > - if (xml != NULL) > - msg = NULL; /* no errors */ > > out: > CU_DEBUG("Filter XML: %s", xml); > diff --git a/src/Virt_Device.c b/src/Virt_Device.c > index faa304d..fd11370 100644 > --- a/src/Virt_Device.c > +++ b/src/Virt_Device.c > @@ -428,7 +428,6 @@ static bool device_instances(const CMPIBroker *broker, > struct inst_list *list) > { > int i; > - bool ret; > uint64_t proc_count = 0; > CMPIInstance *instance = NULL; > > @@ -475,11 +474,7 @@ static bool device_instances(const CMPIBroker *broker, > } > > if (proc_count) { > - ret = vcpu_instances(broker, > - dom, > - ns, > - proc_count, > - list); > + vcpu_instances(broker, dom, ns, proc_count, list); > } > > return true; > @@ -654,16 +649,17 @@ static int proc_dev_list(uint64_t quantity, > struct virt_device **list) > { > int i; > - int rc; > - > > *list = (struct virt_device *)calloc(quantity, > sizeof(struct virt_device)); > > for (i = 0; i< quantity; i++) { > char *dev_num; > + int ret; > > - rc = asprintf(&dev_num, "%d", i); > + ret = asprintf(&dev_num, "%d", i); > + if (ret == -1) > + CU_DEBUG("asprintf error %d" , ret); > > (*list)[i].id = strdup(dev_num); > > @@ -726,7 +722,6 @@ CMPIStatus get_device_by_name(const CMPIBroker *broker, > virDomainPtr dom = NULL; > struct virt_device *dev = NULL; > struct inst_list tmp_list; > - bool rc; > > inst_list_init(&tmp_list); > > @@ -766,24 +761,14 @@ CMPIStatus get_device_by_name(const CMPIBroker *broker, > } > > if (type == CIM_RES_TYPE_PROC) { > - int ret; > int dev_id_num; > - > - ret = sscanf(dev->id, "%d",&dev_id_num); > + sscanf(dev->id, "%d",&dev_id_num); > > - rc = vcpu_inst(broker, > - dom, > - NAMESPACE(reference), > - dev_id_num, > -&tmp_list); > + vcpu_inst(broker, dom, NAMESPACE(reference), > + dev_id_num,&tmp_list); > } else { > - > - rc = device_instances(broker, > - dev, > - 1, > - dom, > - NAMESPACE(reference), > -&tmp_list); > + device_instances(broker, dev, 1, dom, > + NAMESPACE(reference),&tmp_list); > } > > cleanup_virt_devices(&dev, 1); > @@ -799,8 +784,8 @@ CMPIStatus get_device_by_name(const CMPIBroker *broker, > inst_list_free(&tmp_list); > virConnectClose(conn); > > - return s; > -} > + return s; > +} > > CMPIStatus get_device_by_ref(const CMPIBroker *broker, > const CMPIObjectPath *reference, > diff --git a/src/Virt_FilterEntry.c b/src/Virt_FilterEntry.c > index acc3d61..16b211e 100644 > --- a/src/Virt_FilterEntry.c > +++ b/src/Virt_FilterEntry.c > @@ -573,17 +573,12 @@ CMPIStatus enum_filter_rules( > struct acl_filter *filters = NULL; > int i, j, count = 0; > CMPIStatus s = {CMPI_RC_OK, NULL}; > - enum {NONE, MAC, IP} class_type = NONE; > > CU_DEBUG("Reference = %s", REF2STR(reference)); > > - if (STREQC(CLASSNAME(reference), "KVM_Hdr8021Filter")) { > - class_type = MAC; > - } else if (STREQC(CLASSNAME(reference), "KVM_IPHeadersFilter")) { > - class_type = IP; > - } else if (STREQC(CLASSNAME(reference), "KVM_FilterEntry")) { > - class_type = NONE; > - } else { > + if (!STREQC(CLASSNAME(reference), "KVM_Hdr8021Filter")&& > + !STREQC(CLASSNAME(reference), "KVM_IPHeadersFilter")&& > + !STREQC(CLASSNAME(reference), "KVM_FilterEntry")) { > cu_statusf(broker,&s, > CMPI_RC_ERR_FAILED, > "Unrecognized class type"); > diff --git a/src/Virt_RASD.c b/src/Virt_RASD.c > index 4ac2f93..4939f7b 100644 > --- a/src/Virt_RASD.c > +++ b/src/Virt_RASD.c > @@ -289,6 +289,11 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, > uint16_t type; > CMPIStatus s = {CMPI_RC_OK, NULL}; > char *poolid = NULL; > + virConnectPtr conn = NULL; > + virStorageVolPtr vol = NULL; > + virStoragePoolPtr pool = NULL; > + const char *pool_name = NULL; > + int ret = -1; > > get_vol_size(broker, ref, dev->dev.disk.source,&cap); > > @@ -308,7 +313,7 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, > (CMPIValue *)dev->dev.disk.source, > CMPI_chars); > > - virConnectPtr conn = connect_by_classname(broker, CLASSNAME(ref),&s); > + conn = connect_by_classname(broker, CLASSNAME(ref),&s); > if (conn == NULL) { > virt_set_status(broker,&s, > CMPI_RC_ERR_NOT_FOUND, > @@ -317,8 +322,7 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, > goto cont; > } > > - virStorageVolPtr vol = virStorageVolLookupByPath(conn, > - dev->dev.disk.source); > + vol = virStorageVolLookupByPath(conn, dev->dev.disk.source); > if (vol == NULL) { > virt_set_status(broker,&s, > CMPI_RC_ERR_NOT_FOUND, > @@ -327,7 +331,7 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, > goto cont; > } > > - virStoragePoolPtr pool = virStoragePoolLookupByVolume(vol); > + pool = virStoragePoolLookupByVolume(vol); > if (pool == NULL) { > virt_set_status(broker,&s, > CMPI_RC_ERR_NOT_FOUND, > @@ -336,7 +340,7 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, > goto cont; > } > > - const char *pool_name = virStoragePoolGetName(pool); > + pool_name = virStoragePoolGetName(pool); > if (pool_name == NULL) { > virt_set_status(broker,&s, > CMPI_RC_ERR_NOT_FOUND, > @@ -345,8 +349,7 @@ static CMPIStatus set_disk_rasd_params(const CMPIBroker *broker, > goto cont; > } > > - int ret = asprintf(&poolid, "DiskPool/%s", pool_name); > - > + ret = asprintf(&poolid, "DiskPool/%s", pool_name); > if (ret == -1) { > CU_DEBUG("Failed to get disk poolid"); > goto cont; > diff --git a/src/Virt_VSMigrationService.c b/src/Virt_VSMigrationService.c > index 4f48a68..d393787 100644 > --- a/src/Virt_VSMigrationService.c > +++ b/src/Virt_VSMigrationService.c > @@ -1182,7 +1182,6 @@ static CMPIStatus ensure_dom_offline(virDomainPtr dom) > static void clear_infstore_migration_flag(virDomainPtr dom) > { > struct infostore_ctx *infp; > - bool ret = false; > > infp = infostore_open(dom); > if (infp == NULL) { > @@ -1191,7 +1190,7 @@ static void clear_infstore_migration_flag(virDomainPtr dom) > return; > } > > - ret = infostore_set_bool(infp, "migrating", false); > + infostore_set_bool(infp, "migrating", false); > CU_DEBUG("Clearing infostore migrating flag"); > > infostore_close(infp); > @@ -1475,7 +1474,6 @@ static CMPIStatus migrate_do(const CMPIObjectPath *ref, > CMPIStatus s; > CMPIObjectPath *job_op; > struct migration_job *job; > - CMPI_THREAD_TYPE thread; > uint32_t retcode = 1; > CMPIInstance *ind = NULL; > CMPIInstance *inst = NULL; > @@ -1517,7 +1515,7 @@ static CMPIStatus migrate_do(const CMPIObjectPath *ref, > if (!rc) > CU_DEBUG("Failed to raise indication"); > > - thread = _BROKER->xft->newThread((void*)migration_thread, job, 0); > + _BROKER->xft->newThread((void*)migration_thread, job, 0); > > retcode = CIM_SVPC_RETURN_JOB_STARTED; > > diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c > index 5229f56..f8c5f24 100644 > --- a/src/Virt_VirtualSystemManagementService.c > +++ b/src/Virt_VirtualSystemManagementService.c > @@ -1381,10 +1381,9 @@ static const char *input_rasd_to_vdev(CMPIInstance *inst, > struct virt_device *dev) > { > const char *val; > - const char *msg; > > if (cu_get_str_prop(inst, "ResourceSubType",&val) != CMPI_RC_OK) { > - msg = "InputRASD ResourceSubType field not valid"; > + CU_DEBUG("InputRASD ResourceSubType field not valid"); > goto out; > } > dev->dev.input.type = strdup(val); > @@ -1395,7 +1394,7 @@ static const char *input_rasd_to_vdev(CMPIInstance *inst, > else if (STREQC(dev->dev.input.type, "tablet")) > dev->dev.input.bus = strdup("usb"); > else { > - msg = "Invalid value for ResourceSubType in InputRASD"; > + CU_DEBUG("Invalid value for ResourceSubType in InputRASD"); > goto out; > } > } else -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From eblima at linux.vnet.ibm.com Thu Jan 12 14:52:16 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Thu, 12 Jan 2012 12:52:16 -0200 Subject: [Libvirt-cim] [PATCH] Fix a problem with multi-arch In-Reply-To: <20120112062610.GB3609@redhat.com> References: <20120112062610.GB3609@redhat.com> Message-ID: <4F0EF3A0.20701@linux.vnet.ibm.com> On 01/12/2012 04:26 AM, Daniel Veillard wrote: > [ We carry the following patch in RHEL builds, I think it's best applied > upstream :-) ] > Sure thing. One small doubt below. > The /etc/ld.so.conf.d/libvirt-cim.conf file generated conflicted > between 23 bits and 64 bits arches leading to a multi-arch conflict. Can I have some of these 23 bits machine? :P > Simply use a filename based on the expected architecture. > > Signed-off-by: Daniel Veillard > > diff --git a/libvirt-cim.spec.in b/libvirt-cim.spec.in > index f3289db..d78eee7 100644 > --- a/libvirt-cim.spec.in > +++ b/libvirt-cim.spec.in > @@ -54,7 +54,7 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/cmpi/*.la > rm -f $RPM_BUILD_ROOT%{_libdir}/cmpi/*.a > rm -f $RPM_BUILD_ROOT%{_libdir}/libxkutil.so > mkdir -p $RPM_BUILD_ROOT/etc/ld.so.conf.d > -echo %{_libdir}/cmpi > $RPM_BUILD_ROOT/etc/ld.so.conf.d/libvirt-cim.conf > +echo %{_libdir}/cmpi > $RPM_BUILD_ROOT/etc/ld.so.conf.d/libvirt-cim.%{_arch}.conf > mkdir -p $RPM_BUILD_ROOT at INFO_STORE@ > > %clean > @@ -135,7 +135,7 @@ rm -fr $RPM_BUILD_ROOT > %{_datadir}/libvirt-cim/cimv*-cimv2_mof > %{_datadir}/libvirt-cim/*.registration > %{_datadir}/libvirt-cim/cim_schema_*-MOFs.zip > -%{_sysconfdir}/ld.so.conf.d/libvirt-cim.conf > +%{_sysconfdir}/ld.so.conf.d/libvirt-cim.%{_arch}.conf > %config(noreplace) %{_sysconfdir}/libvirt-cim.conf > > %changelog > +1. But s/23/32 before pushing. -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From cvincent at linux.vnet.ibm.com Thu Jan 12 15:02:56 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Thu, 12 Jan 2012 10:02:56 -0500 Subject: [Libvirt-cim] [PATCH] Fix a problem with multi-arch In-Reply-To: <4F0EF3A0.20701@linux.vnet.ibm.com> References: <20120112062610.GB3609@redhat.com> <4F0EF3A0.20701@linux.vnet.ibm.com> Message-ID: <4F0EF620.4020108@linux.vnet.ibm.com> Pushed with comment fixed. On 01/12/2012 09:52 AM, Eduardo Lima (Etrunko) wrote: > On 01/12/2012 04:26 AM, Daniel Veillard wrote: >> [ We carry the following patch in RHEL builds, I think it's best applied >> upstream :-) ] >> > Sure thing. One small doubt below. > >> The /etc/ld.so.conf.d/libvirt-cim.conf file generated conflicted >> between 23 bits and 64 bits arches leading to a multi-arch conflict. > Can I have some of these 23 bits machine? :P > >> Simply use a filename based on the expected architecture. >> >> Signed-off-by: Daniel Veillard >> >> diff --git a/libvirt-cim.spec.in b/libvirt-cim.spec.in >> index f3289db..d78eee7 100644 >> --- a/libvirt-cim.spec.in >> +++ b/libvirt-cim.spec.in >> @@ -54,7 +54,7 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/cmpi/*.la >> rm -f $RPM_BUILD_ROOT%{_libdir}/cmpi/*.a >> rm -f $RPM_BUILD_ROOT%{_libdir}/libxkutil.so >> mkdir -p $RPM_BUILD_ROOT/etc/ld.so.conf.d >> -echo %{_libdir}/cmpi> $RPM_BUILD_ROOT/etc/ld.so.conf.d/libvirt-cim.conf >> +echo %{_libdir}/cmpi> $RPM_BUILD_ROOT/etc/ld.so.conf.d/libvirt-cim.%{_arch}.conf >> mkdir -p $RPM_BUILD_ROOT at INFO_STORE@ >> >> %clean >> @@ -135,7 +135,7 @@ rm -fr $RPM_BUILD_ROOT >> %{_datadir}/libvirt-cim/cimv*-cimv2_mof >> %{_datadir}/libvirt-cim/*.registration >> %{_datadir}/libvirt-cim/cim_schema_*-MOFs.zip >> -%{_sysconfdir}/ld.so.conf.d/libvirt-cim.conf >> +%{_sysconfdir}/ld.so.conf.d/libvirt-cim.%{_arch}.conf >> %config(noreplace) %{_sysconfdir}/libvirt-cim.conf >> >> %changelog >> > +1. But s/23/32 before pushing. > > -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From snmishra at us.ibm.com Thu Jan 12 23:16:31 2012 From: snmishra at us.ibm.com (Sharad Mishra) Date: Thu, 12 Jan 2012 15:16:31 -0800 Subject: [Libvirt-cim] [V3 PATCH 01/10] add source code of libbridge and libnl-3 In-Reply-To: <1326361614-18674-2-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> <1326361614-18674-2-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: << snip >> > diff --git a/libnetwork/libbridge/libbridge.h b/libnetwork/ > libbridge/libbridge.h > new file mode 100644 > index 0000000..39964f2 > --- /dev/null > +++ b/libnetwork/libbridge/libbridge.h > @@ -0,0 +1,119 @@ > +/* > + * Copyright (C) 2000 Lennert Buytenhek Are you using an existing code written by above author? If it is a new code then use - * Copyright IBM Corp. 2012 * * Authors: * Wayne Xia Regards, Sharad Mishra > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of the > + * License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. > + */ From xiawenc at linux.vnet.ibm.com Fri Jan 13 01:45:47 2012 From: xiawenc at linux.vnet.ibm.com (Wayne Xia) Date: Fri, 13 Jan 2012 09:45:47 +0800 Subject: [Libvirt-cim] [V3 PATCH 01/10] add source code of libbridge and libnl-3 In-Reply-To: References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> <1326361614-18674-2-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <4F0F8CCB.1050207@linux.vnet.ibm.com> ? 2012-1-13 7:16, Sharad Mishra ??: > << snip>> > >> diff --git a/libnetwork/libbridge/libbridge.h b/libnetwork/ >> libbridge/libbridge.h >> new file mode 100644 >> index 0000000..39964f2 >> --- /dev/null >> +++ b/libnetwork/libbridge/libbridge.h >> @@ -0,0 +1,119 @@ >> +/* >> + * Copyright (C) 2000 Lennert Buytenhek > > Are you using an existing code written by above author? > If it is a new code then use - > codes in this patch are existing ones have no modification by me, I wonder whether moving source codes of these into libvirt-cim project is acceptable. > * Copyright IBM Corp. 2012 > * > * Authors: > * Wayne Xia > > Regards, > Sharad Mishra > >> + * >> + * This program is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU General Public License as >> + * published by the Free Software Foundation; either version 2 of the >> + * License, or (at your option) any later version. >> + * >> + * This program is distributed in the hope that it will be useful, but >> + * WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >> + * General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program; if not, write to the Free Software >> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >> + */ > > _______________________________________________ > Libvirt-cim mailing list > Libvirt-cim at redhat.com > https://www.redhat.com/mailman/listinfo/libvirt-cim > -- Best Regards Wayne Xia mail:xiawenc at linux.vnet.ibm.com tel:86-010-82450803 From veillard at redhat.com Fri Jan 13 02:56:34 2012 From: veillard at redhat.com (Daniel Veillard) Date: Fri, 13 Jan 2012 10:56:34 +0800 Subject: [Libvirt-cim] [PATCH] Fix a problem with multi-arch In-Reply-To: <4F0EF3A0.20701@linux.vnet.ibm.com> References: <20120112062610.GB3609@redhat.com> <4F0EF3A0.20701@linux.vnet.ibm.com> Message-ID: <20120113025634.GF3609@redhat.com> On Thu, Jan 12, 2012 at 12:52:16PM -0200, Eduardo Lima (Etrunko) wrote: > On 01/12/2012 04:26 AM, Daniel Veillard wrote: > > [ We carry the following patch in RHEL builds, I think it's best applied > > upstream :-) ] > > > > Sure thing. One small doubt below. > > > The /etc/ld.so.conf.d/libvirt-cim.conf file generated conflicted > > between 23 bits and 64 bits arches leading to a multi-arch conflict. > > Can I have some of these 23 bits machine? :P Simple, just take a wire cutter ... The irony is that actually in terms of weird addressing model, your company is still the one who wins without much competition (I'm sure I compiled for 31bits support recently ;-) > > Simply use a filename based on the expected architecture. > > > > Signed-off-by: Daniel Veillard > > > > diff --git a/libvirt-cim.spec.in b/libvirt-cim.spec.in > > index f3289db..d78eee7 100644 > > --- a/libvirt-cim.spec.in > > +++ b/libvirt-cim.spec.in > > @@ -54,7 +54,7 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/cmpi/*.la > > rm -f $RPM_BUILD_ROOT%{_libdir}/cmpi/*.a > > rm -f $RPM_BUILD_ROOT%{_libdir}/libxkutil.so > > mkdir -p $RPM_BUILD_ROOT/etc/ld.so.conf.d > > -echo %{_libdir}/cmpi > $RPM_BUILD_ROOT/etc/ld.so.conf.d/libvirt-cim.conf > > +echo %{_libdir}/cmpi > $RPM_BUILD_ROOT/etc/ld.so.conf.d/libvirt-cim.%{_arch}.conf > > mkdir -p $RPM_BUILD_ROOT at INFO_STORE@ > > > > %clean > > @@ -135,7 +135,7 @@ rm -fr $RPM_BUILD_ROOT > > %{_datadir}/libvirt-cim/cimv*-cimv2_mof > > %{_datadir}/libvirt-cim/*.registration > > %{_datadir}/libvirt-cim/cim_schema_*-MOFs.zip > > -%{_sysconfdir}/ld.so.conf.d/libvirt-cim.conf > > +%{_sysconfdir}/ld.so.conf.d/libvirt-cim.%{_arch}.conf > > %config(noreplace) %{_sysconfdir}/libvirt-cim.conf > > > > %changelog > > > > +1. But s/23/32 before pushing. sure, thanks ! I assume someone from your team is pushing, right ? Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel at veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/ From veillard at redhat.com Fri Jan 13 05:16:17 2012 From: veillard at redhat.com (Daniel Veillard) Date: Fri, 13 Jan 2012 13:16:17 +0800 Subject: [Libvirt-cim] [PATCH] Fix a problem with multi-arch In-Reply-To: <20120113025634.GF3609@redhat.com> References: <20120112062610.GB3609@redhat.com> <4F0EF3A0.20701@linux.vnet.ibm.com> <20120113025634.GF3609@redhat.com> Message-ID: <20120113051617.GH3609@redhat.com> On Fri, Jan 13, 2012 at 10:56:34AM +0800, Daniel Veillard wrote: > On Thu, Jan 12, 2012 at 12:52:16PM -0200, Eduardo Lima (Etrunko) wrote: > > On 01/12/2012 04:26 AM, Daniel Veillard wrote: [...] > > +1. But s/23/32 before pushing. > > sure, thanks ! > I assume someone from your team is pushing, right ? Okay I see Chip pushed it, thanks ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel at veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/ From veillard at redhat.com Fri Jan 13 05:19:40 2012 From: veillard at redhat.com (Daniel Veillard) Date: Fri, 13 Jan 2012 13:19:40 +0800 Subject: [Libvirt-cim] [V3 PATCH 01/10] add source code of libbridge and libnl-3 In-Reply-To: <4F0F8CCB.1050207@linux.vnet.ibm.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> <1326361614-18674-2-git-send-email-xiawenc@linux.vnet.ibm.com> <4F0F8CCB.1050207@linux.vnet.ibm.com> Message-ID: <20120113051940.GI3609@redhat.com> On Fri, Jan 13, 2012 at 09:45:47AM +0800, Wayne Xia wrote: > ? 2012-1-13 7:16, Sharad Mishra ??: > > << snip>> > > > >>diff --git a/libnetwork/libbridge/libbridge.h b/libnetwork/ > >>libbridge/libbridge.h > >>new file mode 100644 > >>index 0000000..39964f2 > >>--- /dev/null > >>+++ b/libnetwork/libbridge/libbridge.h > >>@@ -0,0 +1,119 @@ > >>+/* > >>+ * Copyright (C) 2000 Lennert Buytenhek > > > >Are you using an existing code written by above author? > >If it is a new code then use - > > > codes in this patch are existing ones have no modification by me, I > wonder whether moving source codes of these into libvirt-cim project > is acceptable. In general that's not a good idea. The problem is that if there is a security problem we need to fix the original package and all the copies which were done in various projects. Also such copied code tend to not be updated, makes it easier to bypass APIs boundaries and becomes long term maintenance problems. So unless said code is kind of confidential, i.e. not widely distributed then that something to avoid really, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel at veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/ From eblima at linux.vnet.ibm.com Fri Jan 13 18:01:59 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 13 Jan 2012 16:01:59 -0200 Subject: [Libvirt-cim] [V3 PATCH 01/10] add source code of libbridge and libnl-3 In-Reply-To: <20120113051940.GI3609@redhat.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> <1326361614-18674-2-git-send-email-xiawenc@linux.vnet.ibm.com> <4F0F8CCB.1050207@linux.vnet.ibm.com> <20120113051940.GI3609@redhat.com> Message-ID: <4F107197.5070507@linux.vnet.ibm.com> On 01/13/2012 03:19 AM, Daniel Veillard wrote: > On Fri, Jan 13, 2012 at 09:45:47AM +0800, Wayne Xia wrote: >> ? 2012-1-13 7:16, Sharad Mishra ??: >>> << snip>> >>> >>>> diff --git a/libnetwork/libbridge/libbridge.h b/libnetwork/ >>>> libbridge/libbridge.h >>>> new file mode 100644 >>>> index 0000000..39964f2 >>>> --- /dev/null >>>> +++ b/libnetwork/libbridge/libbridge.h >>>> @@ -0,0 +1,119 @@ >>>> +/* >>>> + * Copyright (C) 2000 Lennert Buytenhek >>> >>> Are you using an existing code written by above author? >>> If it is a new code then use - >>> >> codes in this patch are existing ones have no modification by me, I >> wonder whether moving source codes of these into libvirt-cim project >> is acceptable. > > In general that's not a good idea. > The problem is that if there is a security problem we need to fix the > original package and all the copies which were done in various projects. > Also such copied code tend to not be updated, makes it easier to bypass > APIs boundaries and becomes long term maintenance problems. > So unless said code is kind of confidential, i.e. not widely distributed > then that something to avoid really, > > Daniel > Also there is an issue with license. Libvirt-cim is LGPL while the code you copied is GPL. In this case all files that make use of those features should be relicensed as GPL as well. While I have no experience on this area, I guess it would be not receive the legal approval in the end. Best regards, -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Fri Jan 13 18:36:00 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 13 Jan 2012 16:36:00 -0200 Subject: [Libvirt-cim] [PATCH 0/4] Fix errors raised by Coverity Message-ID: <1326479764-2169-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Yet another series of patches fixing errors revealed by Coverity tool. It would be nice if we had a similar setup so we could run the tool on a regular basis. I started playing with clang a while ago. It also provides a static analyser, but I could not complete the setup by then. https://bugzilla.redhat.com/show_bug.cgi?id=750418 Best regards, Etrunko Eduardo Lima (Etrunko) (4): libxkutil: Fix possible NULL dereferences Fix possible memory leaks xml_parse_test: Fix invalid dereference Fix possible use of unitialized variables libxkutil/cs_util_instance.c | 5 +++++ libxkutil/device_parsing.c | 14 +++++++------- libxkutil/pool_parsing.c | 5 +++-- libxkutil/xml_parse_test.c | 3 +-- libxkutil/xmlgen.c | 8 +++++--- src/Virt_AppliedFilterList.c | 3 ++- src/Virt_Device.c | 28 ++++++++++++++++++++++++++++ src/Virt_DevicePool.c | 19 ++++++++++++++++++- src/Virt_SwitchService.c | 24 ++++++++++++++++++++---- src/Virt_VirtualSystemManagementService.c | 16 ++++++++-------- src/Virt_VirtualSystemSnapshotService.c | 2 +- 11 files changed, 98 insertions(+), 29 deletions(-) -- 1.7.7.5 From eblima at linux.vnet.ibm.com Fri Jan 13 18:36:03 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 13 Jan 2012 16:36:03 -0200 Subject: [Libvirt-cim] [PATCH 3/4] xml_parse_test: Fix invalid dereference In-Reply-To: <1326479764-2169-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326479764-2169-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1326479764-2169-4-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" As revealed by recent Coverity scan report provided by Red Hat: https://bugzilla.redhat.com/show_bug.cgi?id=750418 https://bugzilla.redhat.com/attachment.cgi?id=552325 Error: USE_AFTER_FREE: xml_parse_test.c:239: freed_arg: "free" frees "xml". xml_parse_test.c:242: pass_freed_arg: Passing freed pointer "xml" as an argument to function "printf". Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/xml_parse_test.c | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/libxkutil/xml_parse_test.c b/libxkutil/xml_parse_test.c index 16ceefb..384593d 100644 --- a/libxkutil/xml_parse_test.c +++ b/libxkutil/xml_parse_test.c @@ -236,11 +236,10 @@ static int dominfo_from_file(const char *fname, struct domain **d) ret = get_dominfo_from_xml(xml, d); + printf("XML:\n%s", xml); free(xml); fclose(file); - printf("XML:\n%s", xml); - return ret; } -- 1.7.7.5 From eblima at linux.vnet.ibm.com Fri Jan 13 18:36:04 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 13 Jan 2012 16:36:04 -0200 Subject: [Libvirt-cim] [PATCH 4/4] Fix possible use of unitialized variables In-Reply-To: <1326479764-2169-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326479764-2169-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1326479764-2169-5-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" As revealed by recent Coverity scan report provided by Red Hat: https://bugzilla.redhat.com/show_bug.cgi?id=750418 https://bugzilla.redhat.com/attachment.cgi?id=552325 Error: UNINIT: Virt_VirtualSystemManagementService.c:2798: var_decl: Declaring variable "s" without initializer. Virt_VirtualSystemManagementService.c:2901: uninit_use: Using uninitialized value "s": field "s".msg is uninitialized. Error: UNINIT: Virt_VirtualSystemSnapshotService.c:393: var_decl: Declaring variable "s" without initializer. Virt_VirtualSystemSnapshotService.c:398: uninit_use_in_call: Using uninitialized value "s.rc" when calling "new_context". Virt_VirtualSystemSnapshotService.c:378: read_parm_fld: Reading a parameter field. Signed-off-by: Eduardo Lima (Etrunko) --- src/Virt_VirtualSystemManagementService.c | 2 +- src/Virt_VirtualSystemSnapshotService.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c index 3a0b423..6f42c42 100644 --- a/src/Virt_VirtualSystemManagementService.c +++ b/src/Virt_VirtualSystemManagementService.c @@ -2732,7 +2732,7 @@ static CMPIStatus _update_resources_for(const CMPIContext *context, CMPIInstance *rasd, resmod_fn func) { - CMPIStatus s; + CMPIStatus s = {CMPI_RC_OK, NULL}; struct domain *dominfo = NULL; uint16_t type; char *xml = NULL; diff --git a/src/Virt_VirtualSystemSnapshotService.c b/src/Virt_VirtualSystemSnapshotService.c index 898fa57..aae628f 100644 --- a/src/Virt_VirtualSystemSnapshotService.c +++ b/src/Virt_VirtualSystemSnapshotService.c @@ -390,7 +390,7 @@ static CMPIStatus start_snapshot_job(const CMPIObjectPath *ref, CMPIArgs *argsout) { struct snap_context *ctx; - CMPIStatus s; + CMPIStatus s = {CMPI_RC_OK, NULL}; CMPIObjectPath *job; CMPIObjectPath *vssd; CMPIInstance *inst; -- 1.7.7.5 From eblima at linux.vnet.ibm.com Fri Jan 13 18:36:02 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 13 Jan 2012 16:36:02 -0200 Subject: [Libvirt-cim] [PATCH 2/4] Fix possible memory leaks In-Reply-To: <1326479764-2169-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326479764-2169-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1326479764-2169-3-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" As revealed by recent Coverity scan report provided by Red Hat: https://bugzilla.redhat.com/show_bug.cgi?id=750418 https://bugzilla.redhat.com/attachment.cgi?id=552325 Error: RESOURCE_LEAK: pool_parsing.c:140: alloc_fn: Calling allocation function "realloc". pool_parsing.c:140: var_assign: Assigning: "tmp" = storage returned from "realloc(dev_paths, 8UL * (ct + 1U))". pool_parsing.c:145: var_assign: Assigning: "dev_paths" = "tmp". pool_parsing.c:149: leaked_storage: Variable "tmp" going out of scope leaks the storage it points to. pool_parsing.c:169: leaked_storage: Variable "dev_paths" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: xmlgen.c:891: alloc_fn: Calling allocation function "virt_device_dup". device_parsing.c:873: alloc_fn: Storage is returned from allocation function "calloc". device_parsing.c:873: var_assign: Assigning: "dev" = "calloc(1UL, 152UL)". device_parsing.c:928: return_alloc: Returning allocated memory "dev". xmlgen.c:891: var_assign: Assigning: "dev" = storage returned from "virt_device_dup(_dev)". xmlgen.c:952: leaked_storage: Variable "dev" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: device_parsing.c:354: alloc_fn: Calling allocation function "calloc". device_parsing.c:354: var_assign: Assigning: "vsi_dev" = storage returned from "calloc(1UL, 56UL)". device_parsing.c:385: noescape: Variable "vsi_dev" is not freed or pointed-to in function "memcpy". device_parsing.c:386: leaked_storage: Variable "vsi_dev" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_DevicePool.c:1077: alloc_arg: Calling allocation function "get_diskpool_config" on "pools". Virt_DevicePool.c:161: alloc_arg: "get_disk_parent" allocates memory that is stored into "pools". Virt_DevicePool.c:74: alloc_fn: Storage is returned from allocation function "realloc". Virt_DevicePool.c:74: var_assign: Assigning: "pools" = "realloc(pools, (count + 1) * 24UL)". Virt_DevicePool.c:86: var_assign: Assigning: "*_pools" = "pools". Virt_DevicePool.c:163: var_assign: Assigning: "*_pools" = "pools". Virt_DevicePool.c:1080: leaked_storage: Variable "pools" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_DevicePool.c:404: alloc_arg: Calling allocation function "get_diskpool_config" on "pools". Virt_DevicePool.c:161: alloc_arg: "get_disk_parent" allocates memory that is stored into "pools". Virt_DevicePool.c:74: alloc_fn: Storage is returned from allocation function "realloc". Virt_DevicePool.c:74: var_assign: Assigning: "pools" = "realloc(pools, (count + 1) * 24UL)". Virt_DevicePool.c:86: var_assign: Assigning: "*_pools" = "pools". Virt_DevicePool.c:163: var_assign: Assigning: "*_pools" = "pools". Virt_DevicePool.c:406: leaked_storage: Variable "pools" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_VirtualSystemManagementService.c:415: alloc_fn: Calling allocation function "realloc". Virt_VirtualSystemManagementService.c:415: var_assign: Assigning: "tmp_str_arr" = storage returned from "realloc(domain->os_info.fv.bootlist, bl_size * 8UL)". Virt_VirtualSystemManagementService.c:432: leaked_storage: Variable "tmp_str_arr" going out of scope leaks the storage it points to. Virt_VirtualSystemManagementService.c:440: leaked_storage: Variable "tmp_str_arr" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_VirtualSystemManagementService.c:2834: alloc_fn: Calling allocation function "malloc". Virt_VirtualSystemManagementService.c:2834: var_assign: Assigning: "__retval" = storage returned from "malloc(__len)". Virt_VirtualSystemManagementService.c:2834: noescape: Variable "__retval" is not freed or pointed-to in function "memcpy". Virt_VirtualSystemManagementService.c:2834: overwrite_var: Overwriting "__retval" in call "__retval = (char *)memcpy(__retval, "ResourceAllocationSettingDataCreatedIndication", __len)" leaks the storage that "__retval" points to. Virt_VirtualSystemManagementService.c:2834: var_assign: Assigning: "__retval" = storage returned from "memcpy(__retval, "ResourceAllocationSettingDataCreatedIndication", __len)". Virt_VirtualSystemManagementService.c:2834: var_assign: Assigning: "indication" = "__retval". Virt_VirtualSystemManagementService.c:2901: leaked_storage: Variable "indication" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_VirtualSystemManagementService.c:2837: alloc_fn: Calling allocation function "malloc". Virt_VirtualSystemManagementService.c:2837: var_assign: Assigning: "__retval" = storage returned from "malloc(__len)". Virt_VirtualSystemManagementService.c:2837: noescape: Variable "__retval" is not freed or pointed-to in function "memcpy". Virt_VirtualSystemManagementService.c:2837: overwrite_var: Overwriting "__retval" in call "__retval = (char *)memcpy(__retval, "ResourceAllocationSettingDataDeletedIndication", __len)" leaks the storage that "__retval" points to. Virt_VirtualSystemManagementService.c:2837: var_assign: Assigning: "__retval" = storage returned from "memcpy(__retval, "ResourceAllocationSettingDataDeletedIndication", __len)". Virt_VirtualSystemManagementService.c:2837: var_assign: Assigning: "indication" = "__retval". Virt_VirtualSystemManagementService.c:2901: leaked_storage: Variable "indication" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_VirtualSystemManagementService.c:2840: alloc_fn: Calling allocation function "malloc". Virt_VirtualSystemManagementService.c:2840: var_assign: Assigning: "__retval" = storage returned from "malloc(__len)". Virt_VirtualSystemManagementService.c:2840: noescape: Variable "__retval" is not freed or pointed-to in function "memcpy". Virt_VirtualSystemManagementService.c:2840: overwrite_var: Overwriting "__retval" in call "__retval = (char *)memcpy(__retval, "ResourceAllocationSettingDataModifiedIndication", __len)" leaks the storage that "__retval" points to. Virt_VirtualSystemManagementService.c:2840: var_assign: Assigning: "__retval" = storage returned from "memcpy(__retval, "ResourceAllocationSettingDataModifiedIndication", __len)". Virt_VirtualSystemManagementService.c:2840: var_assign: Assigning: "indication" = "__retval". Virt_VirtualSystemManagementService.c:2901: leaked_storage: Variable "indication" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_AppliedFilterList.c:199: alloc_arg: Calling allocation function "get_domain_list" on "doms". cs_util_instance.c:52: alloc_fn: Storage is returned from allocation function "calloc". cs_util_instance.c:52: var_assign: Assigning: "list" = "calloc(n_names + n_ids, 8UL)". cs_util_instance.c:107: var_assign: Assigning: "*_list" = "list". Virt_AppliedFilterList.c:251: leaked_storage: Variable "doms" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: misc_util.c:275: alloc_arg: Calling allocation function "get_domain_list" on "list". cs_util_instance.c:52: alloc_fn: Storage is returned from allocation function "calloc". cs_util_instance.c:52: var_assign: Assigning: "list" = "calloc(n_names + n_ids, 8UL)". cs_util_instance.c:107: var_assign: Assigning: "*_list" = "list". misc_util.c:277: leaked_storage: Variable "list" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_SwitchService.c:108: alloc_fn: Calling allocation function "popen". Virt_SwitchService.c:108: var_assign: Assigning: "stream" = storage returned from "popen(func, "r")". Virt_SwitchService.c:118: noescape: Variable "stream" is not freed or pointed-to in function "fgets". Virt_SwitchService.c:131: leaked_storage: Variable "stream" going out of scope leaks the storage it points to. Virt_SwitchService.c:142: leaked_storage: Variable "stream" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_SwitchService.c:123: alloc_fn: Calling allocation function "realloc". Virt_SwitchService.c:123: var_assign: Assigning: "tmp_list" = storage returned from "realloc(arr, (i + 1) * 8UL)". Virt_SwitchService.c:134: var_assign: Assigning: "arr" = "tmp_list". Virt_SwitchService.c:142: leaked_storage: Variable "arr" going out of scope leaks the storage it points to. Virt_SwitchService.c:142: leaked_storage: Variable "tmp_list" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_SwitchService.c:236: alloc_fn: Calling allocation function "run_command". Virt_SwitchService.c:123: alloc_fn: Storage is returned from allocation function "realloc". Virt_SwitchService.c:123: var_assign: Assigning: "tmp_list" = "realloc(arr, (i + 1) * 8UL)". Virt_SwitchService.c:134: var_assign: Assigning: "arr" = "tmp_list". Virt_SwitchService.c:151: return_alloc: Returning allocated memory "arr". Virt_SwitchService.c:236: var_assign: Assigning: "if_list" = storage returned from "run_command("/sbin/ifconfig -a | /bin/grep eth | /bin/awk \'{print$1}\'", &count, &s)". /builddir/build/BUILD/libvirt-cim-0.6.0/src/Virt_SwitchService.c:269: leaked_storage: Variable "if_list" going out of scope leaks the storage it points to. Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/cs_util_instance.c | 5 +++++ libxkutil/device_parsing.c | 1 + libxkutil/pool_parsing.c | 5 +++-- libxkutil/xmlgen.c | 4 +++- src/Virt_AppliedFilterList.c | 3 ++- src/Virt_DevicePool.c | 5 ++++- src/Virt_SwitchService.c | 24 ++++++++++++++++++++---- src/Virt_VirtualSystemManagementService.c | 14 +++++++------- 8 files changed, 45 insertions(+), 16 deletions(-) diff --git a/libxkutil/cs_util_instance.c b/libxkutil/cs_util_instance.c index d21f0ff..a383147 100644 --- a/libxkutil/cs_util_instance.c +++ b/libxkutil/cs_util_instance.c @@ -104,6 +104,11 @@ int get_domain_list(virConnectPtr conn, virDomainPtr **_list) free(names); free(ids); + if (idx == 0) { + free(list); + list = NULL; + } + *_list = list; return idx; diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c index b0eccfc..a1e8d6c 100644 --- a/libxkutil/device_parsing.c +++ b/libxkutil/device_parsing.c @@ -382,6 +382,7 @@ static int parse_vsi_device(xmlNode *dnode, struct net_device *vdevs) } memcpy(&(vdevs->vsi), vsi_dev, sizeof(*vsi_dev)); + free(vsi_dev); return 1; err: diff --git a/libxkutil/pool_parsing.c b/libxkutil/pool_parsing.c index f73b0fd..e41fc09 100644 --- a/libxkutil/pool_parsing.c +++ b/libxkutil/pool_parsing.c @@ -163,10 +163,11 @@ static int parse_disk_source(xmlNode *node, struct disk_pool *pool) pool->device_paths_ct = ct; pool->device_paths = dev_paths; + return 1; err: - - return 1; + free(dev_paths); + return 0; } char *get_disk_pool_type(uint16_t type) diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index 96b4e96..7fff4d1 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -928,7 +928,6 @@ char *device_to_xml(struct virt_device *_dev) dominfo->dev_input = dev; break; default: - cleanup_virt_devices(&dev, 1); goto out; } @@ -942,6 +941,9 @@ char *device_to_xml(struct virt_device *_dev) out: CU_DEBUG("Created Device XML:\n%s\n", xml); + if (dev != NULL) + cleanup_virt_devices(&dev, 1); + cleanup_dominfo(&dominfo); xmlFreeNode(root); diff --git a/src/Virt_AppliedFilterList.c b/src/Virt_AppliedFilterList.c index 6567118..bc31c14 100644 --- a/src/Virt_AppliedFilterList.c +++ b/src/Virt_AppliedFilterList.c @@ -197,7 +197,7 @@ static CMPIStatus list_to_net( /* get domains */ dcount = get_domain_list(conn, &doms); - if (dcount < 0) { + if (dcount <= 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, "Failed to get domain list"); @@ -246,6 +246,7 @@ static CMPIStatus list_to_net( } out: + free(doms); virConnectClose(conn); return s; diff --git a/src/Virt_DevicePool.c b/src/Virt_DevicePool.c index ab0baa0..fe5573f 100644 --- a/src/Virt_DevicePool.c +++ b/src/Virt_DevicePool.c @@ -402,8 +402,10 @@ static char *_diskpool_member_of(virConnectPtr conn, char *pool = NULL; count = get_diskpool_config(conn, &pools); - if (count == 0) + if (count == 0) { + free(pools); return NULL; + } for (i = 0; i < count; i++) { if (_diskpool_is_member(conn, &pools[i], file)) { @@ -1091,6 +1093,7 @@ static CMPIStatus diskpool_instance(virConnectPtr conn, count = get_diskpool_config(conn, &pools); if ((id == NULL) && (count == 0)) { CU_DEBUG("No defined DiskPools"); + free(pools); return s; } diff --git a/src/Virt_SwitchService.c b/src/Virt_SwitchService.c index 0d57f54..7e59d38 100644 --- a/src/Virt_SwitchService.c +++ b/src/Virt_SwitchService.c @@ -128,20 +128,19 @@ static char **run_command(char *func, int *len, CMPIStatus *s) { cu_statusf(_BROKER, s, CMPI_RC_ERR_NOT_FOUND, "Failed to realloc"); - return NULL; + goto err; } arr = tmp_list; - string = calloc(len, sizeof(char)); + string = strndup(buff, len); if (string == NULL) { CU_DEBUG("Failed to allocate memory"); cu_statusf(_BROKER, s, CMPI_RC_ERR_NOT_FOUND, "Failed to calloc"); - return NULL; + goto err; } - strncpy(string, buff, len); arr[i] = string; i++; } @@ -149,6 +148,19 @@ static char **run_command(char *func, int *len, CMPIStatus *s) { pclose(stream); *len = i; return arr; + + err: + /* undo everything */ + if (i > 0) { + int count; + for (count = 0; count < i; count++) + free(arr[count]); + } + + free(arr); + pclose(stream); + return NULL; + } static CMPIStatus set_inst_properties(const CMPIBroker *broker, @@ -262,6 +274,10 @@ static CMPIStatus get_switchservice(const CMPIObjectPath *reference, CMSetProperty(inst, "IsVSISupported", (CMPIValue *)&vsi, CMPI_boolean); s.rc = CMPI_RC_OK; + for (i = 0; i < count; i++) + free(if_list[i]); + + free(if_list); out: virConnectClose(conn); *_inst = inst; diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c index f8c5f24..3a0b423 100644 --- a/src/Virt_VirtualSystemManagementService.c +++ b/src/Virt_VirtualSystemManagementService.c @@ -429,6 +429,7 @@ static int bootord_vssd_to_domain(CMPIInstance *inst, if (CMIsNullValue(boot_elem)) { CU_DEBUG("Null BootDevice"); + free(tmp_str_arr); return 0; } @@ -437,6 +438,7 @@ static int bootord_vssd_to_domain(CMPIInstance *inst, if (str == NULL) { CU_DEBUG("Could not extract char pointer from " "CMPIArray"); + free(tmp_str_arr); return 0; } @@ -2766,13 +2768,11 @@ static CMPIStatus _update_resources_for(const CMPIContext *context, } if (func == &resource_add) { - indication = strdup(RASD_IND_CREATED); - } - else if (func == &resource_del) { - indication = strdup(RASD_IND_DELETED); - } - else { - indication = strdup(RASD_IND_MODIFIED); + indication = RASD_IND_CREATED; + } else if (func == &resource_del) { + indication = RASD_IND_DELETED; + } else { + indication = RASD_IND_MODIFIED; char *dummy_name = NULL; if (asprintf(&dummy_name, "%s/%s",dominfo->name, devid) == -1) { -- 1.7.7.5 From eblima at linux.vnet.ibm.com Fri Jan 13 18:36:01 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 13 Jan 2012 16:36:01 -0200 Subject: [Libvirt-cim] [PATCH 1/4] libxkutil: Fix possible NULL dereferences In-Reply-To: <1326479764-2169-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326479764-2169-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1326479764-2169-2-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" As revealed by recent Coverity scan report provided by Red Hat: https://bugzilla.redhat.com/show_bug.cgi?id=750418 https://bugzilla.redhat.com/attachment.cgi?id=552325 Error: FORWARD_NULL: xmlgen.c:100: var_compare_op: Comparing "dev->device" to null implies that "dev->device" might be null. xmlgen.c:115: var_deref_model: Passing null variable "(char *)dev->device" to function "__coverity_strcmp", which dereferences it. Error: FORWARD_NULL: device_parsing.c:615: var_compare_op: Comparing "gdev->type" to null implies that "gdev->type" might be null. device_parsing.c:677: var_deref_model: Passing null variable "gdev->type" to function "cleanup_graphics_device", which dereferences it. device_parsing.c:126: deref_parm_in_call: Function "strcasecmp" dereferences parameter "dev->type". (The dereference is assumed on the basis of the 'nonnull' parameter attribute.) Error: NULL_RETURNS: Virt_DevicePool.c:805: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_DevicePool.c:805: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_DevicePool.c:810: dereference: Dereferencing a pointer that might be null "inst" when calling "mempool_set_total". Virt_DevicePool.c:686: deref_parm: Directly dereferencing parameter "inst". Error: NULL_RETURNS: Virt_DevicePool.c:837: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_DevicePool.c:837: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_DevicePool.c:842: dereference: Dereferencing a pointer that might be null "inst" when calling "procpool_set_total". Virt_DevicePool.c:743: deref_parm: Directly dereferencing parameter "inst". Error: NULL_RETURNS: Virt_Device.c:219: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_Device.c:219: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_Device.c:224: dereference: Dereferencing a pointer that might be null "inst" when calling "graphics_set_attr". Virt_Device.c:202: deref_parm: Directly dereferencing parameter "instance". Error: NULL_RETURNS: Virt_Device.c:133: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_Device.c:133: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_Device.c:138: dereference: Dereferencing a pointer that might be null "inst" when calling "disk_set_name". Virt_Device.c:117: deref_parm: Directly dereferencing parameter "instance". Error: NULL_RETURNS: Virt_Device.c:175: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_Device.c:175: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_Device.c:180: dereference: Dereferencing a pointer that might be null "inst" when calling "mem_set_size". Virt_Device.c:156: deref_parm: Directly dereferencing parameter "instance". Error: NULL_RETURNS: Virt_Device.c:100: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_Device.c:100: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_Device.c:105: dereference: Dereferencing a pointer that might be null "inst" when calling "net_set_type". Virt_Device.c:61: deref_parm: Directly dereferencing parameter "instance". Signed-off-byr Eduardo Lima (Etrunko) --- libxkutil/device_parsing.c | 13 ++++++------- libxkutil/xmlgen.c | 4 ++-- src/Virt_Device.c | 28 ++++++++++++++++++++++++++++ src/Virt_DevicePool.c | 14 ++++++++++++++ 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c index 7eaa63e..b0eccfc 100644 --- a/libxkutil/device_parsing.c +++ b/libxkutil/device_parsing.c @@ -120,15 +120,14 @@ static void cleanup_sdl_device(struct graphics_device *dev) static void cleanup_graphics_device(struct graphics_device *dev) { - if (dev == NULL) + if (dev == NULL || dev->type == NULL) return; - if (STREQC(dev->type, "sdl")) { - cleanup_sdl_device(dev); - } - else { - cleanup_vnc_device(dev); - } + if (STREQC(dev->type, "sdl")) + cleanup_sdl_device(dev); + else + cleanup_vnc_device(dev); + free(dev->type); } diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index d73ffd0..96b4e96 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -112,8 +112,8 @@ static const char *disk_file_xml(xmlNodePtr root, struct disk_device *dev) xmlNewProp(tmp, BAD_CAST "cache", BAD_CAST dev->cache); } - if ((XSTREQ(dev->device, "cdrom")) && - (XSTREQ(dev->source, ""))) { + if (dev->device != NULL && XSTREQ(dev->device, "cdrom") && + XSTREQ(dev->source, "")) { /* This is the situation that user defined a cdrom device without disk in it, so skip generating a line saying "source", for that xml defination for libvirt should not have this defined in this diff --git a/src/Virt_Device.c b/src/Virt_Device.c index fd11370..96797a4 100644 --- a/src/Virt_Device.c +++ b/src/Virt_Device.c @@ -102,6 +102,13 @@ static CMPIInstance *net_instance(const CMPIBroker *broker, "NetworkPort", ns); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Failed to get instance for NetworkPort"); + return NULL; + } + if (!net_set_type(inst, dev)) return NULL; @@ -135,6 +142,13 @@ static CMPIInstance *disk_instance(const CMPIBroker *broker, "LogicalDisk", ns); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Failed to get instance for LogicalDisk"); + return NULL; + } + if (!disk_set_name(inst, dev)) return NULL; @@ -177,6 +191,13 @@ static CMPIInstance *mem_instance(const CMPIBroker *broker, "Memory", ns); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Failed to get instance for Memory"); + return NULL; + } + if (!mem_set_size(inst, dev)) return NULL; @@ -221,6 +242,13 @@ static CMPIInstance *graphics_instance(const CMPIBroker *broker, "DisplayController", ns); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Failed to get instance for DisplayController"); + return NULL; + } + if (!graphics_set_attr(inst, dev)) return NULL; diff --git a/src/Virt_DevicePool.c b/src/Virt_DevicePool.c index a41a378..ab0baa0 100644 --- a/src/Virt_DevicePool.c +++ b/src/Virt_DevicePool.c @@ -807,6 +807,13 @@ static CMPIStatus mempool_instance(virConnectPtr conn, "MemoryPool", ns); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Failed to get instance for MemoryPool"); + return s; + } + mempool_set_total(inst, conn); mempool_set_consumed(inst, conn); @@ -839,6 +846,13 @@ static CMPIStatus procpool_instance(virConnectPtr conn, "ProcessorPool", ns); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Failed to get instance for ProcessorPool"); + return s; + } + procpool_set_total(inst, conn); set_params(inst, CIM_RES_TYPE_PROC, id, "Processors", NULL, true); -- 1.7.7.5 From eblima at linux.vnet.ibm.com Fri Jan 13 18:46:57 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 13 Jan 2012 16:46:57 -0200 Subject: [Libvirt-cim] [PATCH 1/4] libxkutil: Fix possible NULL dereferences In-Reply-To: <1326479764-2169-2-git-send-email-eblima@linux.vnet.ibm.com> References: <1326479764-2169-1-git-send-email-eblima@linux.vnet.ibm.com> <1326479764-2169-2-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F107C21.5080006@linux.vnet.ibm.com> On 01/13/2012 04:36 PM, Eduardo Lima (Etrunko) wrote: [snip] > diff --git a/src/Virt_Device.c b/src/Virt_Device.c > index fd11370..96797a4 100644 > --- a/src/Virt_Device.c > +++ b/src/Virt_Device.c > @@ -102,6 +102,13 @@ static CMPIInstance *net_instance(const CMPIBroker *broker, > "NetworkPort", > ns); > > + if (inst == NULL) { > + cu_statusf(broker, &s, > + CMPI_RC_ERR_FAILED, > + "Failed to get instance for NetworkPort"); > + return NULL; > + } > + > if (!net_set_type(inst, dev)) > return NULL; > > @@ -135,6 +142,13 @@ static CMPIInstance *disk_instance(const CMPIBroker *broker, > "LogicalDisk", > ns); > > + if (inst == NULL) { > + cu_statusf(broker, &s, > + CMPI_RC_ERR_FAILED, > + "Failed to get instance for LogicalDisk"); > + return NULL; > + } > + > if (!disk_set_name(inst, dev)) > return NULL; > > @@ -177,6 +191,13 @@ static CMPIInstance *mem_instance(const CMPIBroker *broker, > "Memory", > ns); > > + if (inst == NULL) { > + cu_statusf(broker, &s, > + CMPI_RC_ERR_FAILED, > + "Failed to get instance for Memory"); > + return NULL; > + } > + > if (!mem_set_size(inst, dev)) > return NULL; > > @@ -221,6 +242,13 @@ static CMPIInstance *graphics_instance(const CMPIBroker *broker, > "DisplayController", > ns); > > + if (inst == NULL) { > + cu_statusf(broker, &s, > + CMPI_RC_ERR_FAILED, > + "Failed to get instance for DisplayController"); > + return NULL; > + } > + > if (!graphics_set_attr(inst, dev)) > return NULL; > Woops, this patch does not compiles. Sorry about that. I'm sending a new version of the series. Cheers, -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Fri Jan 13 18:53:19 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 13 Jan 2012 16:53:19 -0200 Subject: [Libvirt-cim] [PATCH 1/4] libxkutil: Fix possible NULL dereferences In-Reply-To: <1326480802-6035-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326480802-6035-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1326480802-6035-2-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" As revealed by recent Coverity scan report provided by Red Hat: https://bugzilla.redhat.com/show_bug.cgi?id=750418 https://bugzilla.redhat.com/attachment.cgi?id=552325 Error: FORWARD_NULL: xmlgen.c:100: var_compare_op: Comparing "dev->device" to null implies that "dev->device" might be null. xmlgen.c:115: var_deref_model: Passing null variable "(char *)dev->device" to function "__coverity_strcmp", which dereferences it. Error: FORWARD_NULL: device_parsing.c:615: var_compare_op: Comparing "gdev->type" to null implies that "gdev->type" might be null. device_parsing.c:677: var_deref_model: Passing null variable "gdev->type" to function "cleanup_graphics_device", which dereferences it. device_parsing.c:126: deref_parm_in_call: Function "strcasecmp" dereferences parameter "dev->type". (The dereference is assumed on the basis of the 'nonnull' parameter attribute.) Error: NULL_RETURNS: Virt_DevicePool.c:805: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_DevicePool.c:805: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_DevicePool.c:810: dereference: Dereferencing a pointer that might be null "inst" when calling "mempool_set_total". Virt_DevicePool.c:686: deref_parm: Directly dereferencing parameter "inst". Error: NULL_RETURNS: Virt_DevicePool.c:837: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_DevicePool.c:837: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_DevicePool.c:842: dereference: Dereferencing a pointer that might be null "inst" when calling "procpool_set_total". Virt_DevicePool.c:743: deref_parm: Directly dereferencing parameter "inst". Error: NULL_RETURNS: Virt_Device.c:219: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_Device.c:219: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_Device.c:224: dereference: Dereferencing a pointer that might be null "inst" when calling "graphics_set_attr". Virt_Device.c:202: deref_parm: Directly dereferencing parameter "instance". Error: NULL_RETURNS: Virt_Device.c:133: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_Device.c:133: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_Device.c:138: dereference: Dereferencing a pointer that might be null "inst" when calling "disk_set_name". Virt_Device.c:117: deref_parm: Directly dereferencing parameter "instance". Error: NULL_RETURNS: Virt_Device.c:175: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_Device.c:175: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_Device.c:180: dereference: Dereferencing a pointer that might be null "inst" when calling "mem_set_size". Virt_Device.c:156: deref_parm: Directly dereferencing parameter "instance". Error: NULL_RETURNS: Virt_Device.c:100: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_Device.c:100: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_Device.c:105: dereference: Dereferencing a pointer that might be null "inst" when calling "net_set_type". Virt_Device.c:61: deref_parm: Directly dereferencing parameter "instance". Signed-off-byr Eduardo Lima (Etrunko) --- libxkutil/device_parsing.c | 13 ++++++------- libxkutil/xmlgen.c | 4 ++-- src/Virt_Device.c | 20 ++++++++++++++++++++ src/Virt_DevicePool.c | 14 ++++++++++++++ 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c index 7eaa63e..b0eccfc 100644 --- a/libxkutil/device_parsing.c +++ b/libxkutil/device_parsing.c @@ -120,15 +120,14 @@ static void cleanup_sdl_device(struct graphics_device *dev) static void cleanup_graphics_device(struct graphics_device *dev) { - if (dev == NULL) + if (dev == NULL || dev->type == NULL) return; - if (STREQC(dev->type, "sdl")) { - cleanup_sdl_device(dev); - } - else { - cleanup_vnc_device(dev); - } + if (STREQC(dev->type, "sdl")) + cleanup_sdl_device(dev); + else + cleanup_vnc_device(dev); + free(dev->type); } diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index d73ffd0..96b4e96 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -112,8 +112,8 @@ static const char *disk_file_xml(xmlNodePtr root, struct disk_device *dev) xmlNewProp(tmp, BAD_CAST "cache", BAD_CAST dev->cache); } - if ((XSTREQ(dev->device, "cdrom")) && - (XSTREQ(dev->source, ""))) { + if (dev->device != NULL && XSTREQ(dev->device, "cdrom") && + XSTREQ(dev->source, "")) { /* This is the situation that user defined a cdrom device without disk in it, so skip generating a line saying "source", for that xml defination for libvirt should not have this defined in this diff --git a/src/Virt_Device.c b/src/Virt_Device.c index fd11370..abe3d6f 100644 --- a/src/Virt_Device.c +++ b/src/Virt_Device.c @@ -102,6 +102,11 @@ static CMPIInstance *net_instance(const CMPIBroker *broker, "NetworkPort", ns); + if (inst == NULL) { + CU_DEBUG("Failed to get instance for NetworkPort"); + return NULL; + } + if (!net_set_type(inst, dev)) return NULL; @@ -135,6 +140,11 @@ static CMPIInstance *disk_instance(const CMPIBroker *broker, "LogicalDisk", ns); + if (inst == NULL) { + CU_DEBUG("Failed to get instance for LogicalDisk"); + return NULL; + } + if (!disk_set_name(inst, dev)) return NULL; @@ -177,6 +187,11 @@ static CMPIInstance *mem_instance(const CMPIBroker *broker, "Memory", ns); + if (inst == NULL) { + CU_DEBUG("Failed to get instance for Memory"); + return NULL; + } + if (!mem_set_size(inst, dev)) return NULL; @@ -221,6 +236,11 @@ static CMPIInstance *graphics_instance(const CMPIBroker *broker, "DisplayController", ns); + if (inst == NULL) { + CU_DEBUG("Failed to get instance for DisplayController"); + return NULL; + } + if (!graphics_set_attr(inst, dev)) return NULL; diff --git a/src/Virt_DevicePool.c b/src/Virt_DevicePool.c index a41a378..ab0baa0 100644 --- a/src/Virt_DevicePool.c +++ b/src/Virt_DevicePool.c @@ -807,6 +807,13 @@ static CMPIStatus mempool_instance(virConnectPtr conn, "MemoryPool", ns); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Failed to get instance for MemoryPool"); + return s; + } + mempool_set_total(inst, conn); mempool_set_consumed(inst, conn); @@ -839,6 +846,13 @@ static CMPIStatus procpool_instance(virConnectPtr conn, "ProcessorPool", ns); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Failed to get instance for ProcessorPool"); + return s; + } + procpool_set_total(inst, conn); set_params(inst, CIM_RES_TYPE_PROC, id, "Processors", NULL, true); -- 1.7.7.5 From eblima at linux.vnet.ibm.com Fri Jan 13 18:53:20 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 13 Jan 2012 16:53:20 -0200 Subject: [Libvirt-cim] [PATCH 2/4] Fix possible memory leaks In-Reply-To: <1326480802-6035-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326480802-6035-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1326480802-6035-3-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" As revealed by recent Coverity scan report provided by Red Hat: https://bugzilla.redhat.com/show_bug.cgi?id=750418 https://bugzilla.redhat.com/attachment.cgi?id=552325 Error: RESOURCE_LEAK: pool_parsing.c:140: alloc_fn: Calling allocation function "realloc". pool_parsing.c:140: var_assign: Assigning: "tmp" = storage returned from "realloc(dev_paths, 8UL * (ct + 1U))". pool_parsing.c:145: var_assign: Assigning: "dev_paths" = "tmp". pool_parsing.c:149: leaked_storage: Variable "tmp" going out of scope leaks the storage it points to. pool_parsing.c:169: leaked_storage: Variable "dev_paths" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: xmlgen.c:891: alloc_fn: Calling allocation function "virt_device_dup". device_parsing.c:873: alloc_fn: Storage is returned from allocation function "calloc". device_parsing.c:873: var_assign: Assigning: "dev" = "calloc(1UL, 152UL)". device_parsing.c:928: return_alloc: Returning allocated memory "dev". xmlgen.c:891: var_assign: Assigning: "dev" = storage returned from "virt_device_dup(_dev)". xmlgen.c:952: leaked_storage: Variable "dev" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: device_parsing.c:354: alloc_fn: Calling allocation function "calloc". device_parsing.c:354: var_assign: Assigning: "vsi_dev" = storage returned from "calloc(1UL, 56UL)". device_parsing.c:385: noescape: Variable "vsi_dev" is not freed or pointed-to in function "memcpy". device_parsing.c:386: leaked_storage: Variable "vsi_dev" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_DevicePool.c:1077: alloc_arg: Calling allocation function "get_diskpool_config" on "pools". Virt_DevicePool.c:161: alloc_arg: "get_disk_parent" allocates memory that is stored into "pools". Virt_DevicePool.c:74: alloc_fn: Storage is returned from allocation function "realloc". Virt_DevicePool.c:74: var_assign: Assigning: "pools" = "realloc(pools, (count + 1) * 24UL)". Virt_DevicePool.c:86: var_assign: Assigning: "*_pools" = "pools". Virt_DevicePool.c:163: var_assign: Assigning: "*_pools" = "pools". Virt_DevicePool.c:1080: leaked_storage: Variable "pools" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_DevicePool.c:404: alloc_arg: Calling allocation function "get_diskpool_config" on "pools". Virt_DevicePool.c:161: alloc_arg: "get_disk_parent" allocates memory that is stored into "pools". Virt_DevicePool.c:74: alloc_fn: Storage is returned from allocation function "realloc". Virt_DevicePool.c:74: var_assign: Assigning: "pools" = "realloc(pools, (count + 1) * 24UL)". Virt_DevicePool.c:86: var_assign: Assigning: "*_pools" = "pools". Virt_DevicePool.c:163: var_assign: Assigning: "*_pools" = "pools". Virt_DevicePool.c:406: leaked_storage: Variable "pools" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_VirtualSystemManagementService.c:415: alloc_fn: Calling allocation function "realloc". Virt_VirtualSystemManagementService.c:415: var_assign: Assigning: "tmp_str_arr" = storage returned from "realloc(domain->os_info.fv.bootlist, bl_size * 8UL)". Virt_VirtualSystemManagementService.c:432: leaked_storage: Variable "tmp_str_arr" going out of scope leaks the storage it points to. Virt_VirtualSystemManagementService.c:440: leaked_storage: Variable "tmp_str_arr" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_VirtualSystemManagementService.c:2834: alloc_fn: Calling allocation function "malloc". Virt_VirtualSystemManagementService.c:2834: var_assign: Assigning: "__retval" = storage returned from "malloc(__len)". Virt_VirtualSystemManagementService.c:2834: noescape: Variable "__retval" is not freed or pointed-to in function "memcpy". Virt_VirtualSystemManagementService.c:2834: overwrite_var: Overwriting "__retval" in call "__retval = (char *)memcpy(__retval, "ResourceAllocationSettingDataCreatedIndication", __len)" leaks the storage that "__retval" points to. Virt_VirtualSystemManagementService.c:2834: var_assign: Assigning: "__retval" = storage returned from "memcpy(__retval, "ResourceAllocationSettingDataCreatedIndication", __len)". Virt_VirtualSystemManagementService.c:2834: var_assign: Assigning: "indication" = "__retval". Virt_VirtualSystemManagementService.c:2901: leaked_storage: Variable "indication" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_VirtualSystemManagementService.c:2837: alloc_fn: Calling allocation function "malloc". Virt_VirtualSystemManagementService.c:2837: var_assign: Assigning: "__retval" = storage returned from "malloc(__len)". Virt_VirtualSystemManagementService.c:2837: noescape: Variable "__retval" is not freed or pointed-to in function "memcpy". Virt_VirtualSystemManagementService.c:2837: overwrite_var: Overwriting "__retval" in call "__retval = (char *)memcpy(__retval, "ResourceAllocationSettingDataDeletedIndication", __len)" leaks the storage that "__retval" points to. Virt_VirtualSystemManagementService.c:2837: var_assign: Assigning: "__retval" = storage returned from "memcpy(__retval, "ResourceAllocationSettingDataDeletedIndication", __len)". Virt_VirtualSystemManagementService.c:2837: var_assign: Assigning: "indication" = "__retval". Virt_VirtualSystemManagementService.c:2901: leaked_storage: Variable "indication" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_VirtualSystemManagementService.c:2840: alloc_fn: Calling allocation function "malloc". Virt_VirtualSystemManagementService.c:2840: var_assign: Assigning: "__retval" = storage returned from "malloc(__len)". Virt_VirtualSystemManagementService.c:2840: noescape: Variable "__retval" is not freed or pointed-to in function "memcpy". Virt_VirtualSystemManagementService.c:2840: overwrite_var: Overwriting "__retval" in call "__retval = (char *)memcpy(__retval, "ResourceAllocationSettingDataModifiedIndication", __len)" leaks the storage that "__retval" points to. Virt_VirtualSystemManagementService.c:2840: var_assign: Assigning: "__retval" = storage returned from "memcpy(__retval, "ResourceAllocationSettingDataModifiedIndication", __len)". Virt_VirtualSystemManagementService.c:2840: var_assign: Assigning: "indication" = "__retval". Virt_VirtualSystemManagementService.c:2901: leaked_storage: Variable "indication" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_AppliedFilterList.c:199: alloc_arg: Calling allocation function "get_domain_list" on "doms". cs_util_instance.c:52: alloc_fn: Storage is returned from allocation function "calloc". cs_util_instance.c:52: var_assign: Assigning: "list" = "calloc(n_names + n_ids, 8UL)". cs_util_instance.c:107: var_assign: Assigning: "*_list" = "list". Virt_AppliedFilterList.c:251: leaked_storage: Variable "doms" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: misc_util.c:275: alloc_arg: Calling allocation function "get_domain_list" on "list". cs_util_instance.c:52: alloc_fn: Storage is returned from allocation function "calloc". cs_util_instance.c:52: var_assign: Assigning: "list" = "calloc(n_names + n_ids, 8UL)". cs_util_instance.c:107: var_assign: Assigning: "*_list" = "list". misc_util.c:277: leaked_storage: Variable "list" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_SwitchService.c:108: alloc_fn: Calling allocation function "popen". Virt_SwitchService.c:108: var_assign: Assigning: "stream" = storage returned from "popen(func, "r")". Virt_SwitchService.c:118: noescape: Variable "stream" is not freed or pointed-to in function "fgets". Virt_SwitchService.c:131: leaked_storage: Variable "stream" going out of scope leaks the storage it points to. Virt_SwitchService.c:142: leaked_storage: Variable "stream" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_SwitchService.c:123: alloc_fn: Calling allocation function "realloc". Virt_SwitchService.c:123: var_assign: Assigning: "tmp_list" = storage returned from "realloc(arr, (i + 1) * 8UL)". Virt_SwitchService.c:134: var_assign: Assigning: "arr" = "tmp_list". Virt_SwitchService.c:142: leaked_storage: Variable "arr" going out of scope leaks the storage it points to. Virt_SwitchService.c:142: leaked_storage: Variable "tmp_list" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_SwitchService.c:236: alloc_fn: Calling allocation function "run_command". Virt_SwitchService.c:123: alloc_fn: Storage is returned from allocation function "realloc". Virt_SwitchService.c:123: var_assign: Assigning: "tmp_list" = "realloc(arr, (i + 1) * 8UL)". Virt_SwitchService.c:134: var_assign: Assigning: "arr" = "tmp_list". Virt_SwitchService.c:151: return_alloc: Returning allocated memory "arr". Virt_SwitchService.c:236: var_assign: Assigning: "if_list" = storage returned from "run_command("/sbin/ifconfig -a | /bin/grep eth | /bin/awk \'{print$1}\'", &count, &s)". /builddir/build/BUILD/libvirt-cim-0.6.0/src/Virt_SwitchService.c:269: leaked_storage: Variable "if_list" going out of scope leaks the storage it points to. Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/cs_util_instance.c | 5 +++++ libxkutil/device_parsing.c | 1 + libxkutil/pool_parsing.c | 5 +++-- libxkutil/xmlgen.c | 4 +++- src/Virt_AppliedFilterList.c | 3 ++- src/Virt_DevicePool.c | 5 ++++- src/Virt_SwitchService.c | 24 ++++++++++++++++++++---- src/Virt_VirtualSystemManagementService.c | 14 +++++++------- 8 files changed, 45 insertions(+), 16 deletions(-) diff --git a/libxkutil/cs_util_instance.c b/libxkutil/cs_util_instance.c index d21f0ff..a383147 100644 --- a/libxkutil/cs_util_instance.c +++ b/libxkutil/cs_util_instance.c @@ -104,6 +104,11 @@ int get_domain_list(virConnectPtr conn, virDomainPtr **_list) free(names); free(ids); + if (idx == 0) { + free(list); + list = NULL; + } + *_list = list; return idx; diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c index b0eccfc..a1e8d6c 100644 --- a/libxkutil/device_parsing.c +++ b/libxkutil/device_parsing.c @@ -382,6 +382,7 @@ static int parse_vsi_device(xmlNode *dnode, struct net_device *vdevs) } memcpy(&(vdevs->vsi), vsi_dev, sizeof(*vsi_dev)); + free(vsi_dev); return 1; err: diff --git a/libxkutil/pool_parsing.c b/libxkutil/pool_parsing.c index f73b0fd..e41fc09 100644 --- a/libxkutil/pool_parsing.c +++ b/libxkutil/pool_parsing.c @@ -163,10 +163,11 @@ static int parse_disk_source(xmlNode *node, struct disk_pool *pool) pool->device_paths_ct = ct; pool->device_paths = dev_paths; + return 1; err: - - return 1; + free(dev_paths); + return 0; } char *get_disk_pool_type(uint16_t type) diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index 96b4e96..7fff4d1 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -928,7 +928,6 @@ char *device_to_xml(struct virt_device *_dev) dominfo->dev_input = dev; break; default: - cleanup_virt_devices(&dev, 1); goto out; } @@ -942,6 +941,9 @@ char *device_to_xml(struct virt_device *_dev) out: CU_DEBUG("Created Device XML:\n%s\n", xml); + if (dev != NULL) + cleanup_virt_devices(&dev, 1); + cleanup_dominfo(&dominfo); xmlFreeNode(root); diff --git a/src/Virt_AppliedFilterList.c b/src/Virt_AppliedFilterList.c index 6567118..bc31c14 100644 --- a/src/Virt_AppliedFilterList.c +++ b/src/Virt_AppliedFilterList.c @@ -197,7 +197,7 @@ static CMPIStatus list_to_net( /* get domains */ dcount = get_domain_list(conn, &doms); - if (dcount < 0) { + if (dcount <= 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, "Failed to get domain list"); @@ -246,6 +246,7 @@ static CMPIStatus list_to_net( } out: + free(doms); virConnectClose(conn); return s; diff --git a/src/Virt_DevicePool.c b/src/Virt_DevicePool.c index ab0baa0..fe5573f 100644 --- a/src/Virt_DevicePool.c +++ b/src/Virt_DevicePool.c @@ -402,8 +402,10 @@ static char *_diskpool_member_of(virConnectPtr conn, char *pool = NULL; count = get_diskpool_config(conn, &pools); - if (count == 0) + if (count == 0) { + free(pools); return NULL; + } for (i = 0; i < count; i++) { if (_diskpool_is_member(conn, &pools[i], file)) { @@ -1091,6 +1093,7 @@ static CMPIStatus diskpool_instance(virConnectPtr conn, count = get_diskpool_config(conn, &pools); if ((id == NULL) && (count == 0)) { CU_DEBUG("No defined DiskPools"); + free(pools); return s; } diff --git a/src/Virt_SwitchService.c b/src/Virt_SwitchService.c index 0d57f54..7e59d38 100644 --- a/src/Virt_SwitchService.c +++ b/src/Virt_SwitchService.c @@ -128,20 +128,19 @@ static char **run_command(char *func, int *len, CMPIStatus *s) { cu_statusf(_BROKER, s, CMPI_RC_ERR_NOT_FOUND, "Failed to realloc"); - return NULL; + goto err; } arr = tmp_list; - string = calloc(len, sizeof(char)); + string = strndup(buff, len); if (string == NULL) { CU_DEBUG("Failed to allocate memory"); cu_statusf(_BROKER, s, CMPI_RC_ERR_NOT_FOUND, "Failed to calloc"); - return NULL; + goto err; } - strncpy(string, buff, len); arr[i] = string; i++; } @@ -149,6 +148,19 @@ static char **run_command(char *func, int *len, CMPIStatus *s) { pclose(stream); *len = i; return arr; + + err: + /* undo everything */ + if (i > 0) { + int count; + for (count = 0; count < i; count++) + free(arr[count]); + } + + free(arr); + pclose(stream); + return NULL; + } static CMPIStatus set_inst_properties(const CMPIBroker *broker, @@ -262,6 +274,10 @@ static CMPIStatus get_switchservice(const CMPIObjectPath *reference, CMSetProperty(inst, "IsVSISupported", (CMPIValue *)&vsi, CMPI_boolean); s.rc = CMPI_RC_OK; + for (i = 0; i < count; i++) + free(if_list[i]); + + free(if_list); out: virConnectClose(conn); *_inst = inst; diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c index f8c5f24..3a0b423 100644 --- a/src/Virt_VirtualSystemManagementService.c +++ b/src/Virt_VirtualSystemManagementService.c @@ -429,6 +429,7 @@ static int bootord_vssd_to_domain(CMPIInstance *inst, if (CMIsNullValue(boot_elem)) { CU_DEBUG("Null BootDevice"); + free(tmp_str_arr); return 0; } @@ -437,6 +438,7 @@ static int bootord_vssd_to_domain(CMPIInstance *inst, if (str == NULL) { CU_DEBUG("Could not extract char pointer from " "CMPIArray"); + free(tmp_str_arr); return 0; } @@ -2766,13 +2768,11 @@ static CMPIStatus _update_resources_for(const CMPIContext *context, } if (func == &resource_add) { - indication = strdup(RASD_IND_CREATED); - } - else if (func == &resource_del) { - indication = strdup(RASD_IND_DELETED); - } - else { - indication = strdup(RASD_IND_MODIFIED); + indication = RASD_IND_CREATED; + } else if (func == &resource_del) { + indication = RASD_IND_DELETED; + } else { + indication = RASD_IND_MODIFIED; char *dummy_name = NULL; if (asprintf(&dummy_name, "%s/%s",dominfo->name, devid) == -1) { -- 1.7.7.5 From eblima at linux.vnet.ibm.com Fri Jan 13 18:53:18 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 13 Jan 2012 16:53:18 -0200 Subject: [Libvirt-cim] [PATCH v2 0/4] Fix errors raised by Coverity tool Message-ID: <1326480802-6035-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Yet another series of patches fixing errors revealed by Coverity tool. It would be nice if we had a similar setup so we could run the tool on a regular basis. I started playing with clang a while ago. It also provides a static analyser, but I could not complete the setup by then. https://bugzilla.redhat.com/show_bug.cgi?id=750418 Changes from v1: - Fix compilation error in Patch 1 Best regards, Etrunko Eduardo Lima (Etrunko) (4): libxkutil: Fix possible NULL dereferences Fix possible memory leaks xml_parse_test: Fix invalid dereference Fix possible use of unitialized variables libxkutil/cs_util_instance.c | 5 +++++ libxkutil/device_parsing.c | 14 +++++++------- libxkutil/pool_parsing.c | 5 +++-- libxkutil/xml_parse_test.c | 3 +-- libxkutil/xmlgen.c | 8 +++++--- src/Virt_AppliedFilterList.c | 3 ++- src/Virt_Device.c | 20 ++++++++++++++++++++ src/Virt_DevicePool.c | 19 ++++++++++++++++++- src/Virt_SwitchService.c | 24 ++++++++++++++++++++---- src/Virt_VirtualSystemManagementService.c | 16 ++++++++-------- src/Virt_VirtualSystemSnapshotService.c | 2 +- 11 files changed, 90 insertions(+), 29 deletions(-) -- 1.7.7.5 From eblima at linux.vnet.ibm.com Fri Jan 13 18:53:21 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 13 Jan 2012 16:53:21 -0200 Subject: [Libvirt-cim] [PATCH 3/4] xml_parse_test: Fix invalid dereference In-Reply-To: <1326480802-6035-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326480802-6035-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1326480802-6035-4-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" As revealed by recent Coverity scan report provided by Red Hat: https://bugzilla.redhat.com/show_bug.cgi?id=750418 https://bugzilla.redhat.com/attachment.cgi?id=552325 Error: USE_AFTER_FREE: xml_parse_test.c:239: freed_arg: "free" frees "xml". xml_parse_test.c:242: pass_freed_arg: Passing freed pointer "xml" as an argument to function "printf". Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/xml_parse_test.c | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/libxkutil/xml_parse_test.c b/libxkutil/xml_parse_test.c index 16ceefb..384593d 100644 --- a/libxkutil/xml_parse_test.c +++ b/libxkutil/xml_parse_test.c @@ -236,11 +236,10 @@ static int dominfo_from_file(const char *fname, struct domain **d) ret = get_dominfo_from_xml(xml, d); + printf("XML:\n%s", xml); free(xml); fclose(file); - printf("XML:\n%s", xml); - return ret; } -- 1.7.7.5 From eblima at linux.vnet.ibm.com Fri Jan 13 18:53:22 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 13 Jan 2012 16:53:22 -0200 Subject: [Libvirt-cim] [PATCH 4/4] Fix possible use of unitialized variables In-Reply-To: <1326480802-6035-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326480802-6035-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1326480802-6035-5-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" As revealed by recent Coverity scan report provided by Red Hat: https://bugzilla.redhat.com/show_bug.cgi?id=750418 https://bugzilla.redhat.com/attachment.cgi?id=552325 Error: UNINIT: Virt_VirtualSystemManagementService.c:2798: var_decl: Declaring variable "s" without initializer. Virt_VirtualSystemManagementService.c:2901: uninit_use: Using uninitialized value "s": field "s".msg is uninitialized. Error: UNINIT: Virt_VirtualSystemSnapshotService.c:393: var_decl: Declaring variable "s" without initializer. Virt_VirtualSystemSnapshotService.c:398: uninit_use_in_call: Using uninitialized value "s.rc" when calling "new_context". Virt_VirtualSystemSnapshotService.c:378: read_parm_fld: Reading a parameter field. Signed-off-by: Eduardo Lima (Etrunko) --- src/Virt_VirtualSystemManagementService.c | 2 +- src/Virt_VirtualSystemSnapshotService.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c index 3a0b423..6f42c42 100644 --- a/src/Virt_VirtualSystemManagementService.c +++ b/src/Virt_VirtualSystemManagementService.c @@ -2732,7 +2732,7 @@ static CMPIStatus _update_resources_for(const CMPIContext *context, CMPIInstance *rasd, resmod_fn func) { - CMPIStatus s; + CMPIStatus s = {CMPI_RC_OK, NULL}; struct domain *dominfo = NULL; uint16_t type; char *xml = NULL; diff --git a/src/Virt_VirtualSystemSnapshotService.c b/src/Virt_VirtualSystemSnapshotService.c index 898fa57..aae628f 100644 --- a/src/Virt_VirtualSystemSnapshotService.c +++ b/src/Virt_VirtualSystemSnapshotService.c @@ -390,7 +390,7 @@ static CMPIStatus start_snapshot_job(const CMPIObjectPath *ref, CMPIArgs *argsout) { struct snap_context *ctx; - CMPIStatus s; + CMPIStatus s = {CMPI_RC_OK, NULL}; CMPIObjectPath *job; CMPIObjectPath *vssd; CMPIInstance *inst; -- 1.7.7.5 From veillard at redhat.com Mon Jan 16 02:35:10 2012 From: veillard at redhat.com (Daniel Veillard) Date: Mon, 16 Jan 2012 10:35:10 +0800 Subject: [Libvirt-cim] [V3 PATCH 01/10] add source code of libbridge and libnl-3 In-Reply-To: <4F107197.5070507@linux.vnet.ibm.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> <1326361614-18674-2-git-send-email-xiawenc@linux.vnet.ibm.com> <4F0F8CCB.1050207@linux.vnet.ibm.com> <20120113051940.GI3609@redhat.com> <4F107197.5070507@linux.vnet.ibm.com> Message-ID: <20120116023510.GL3609@redhat.com> On Fri, Jan 13, 2012 at 04:01:59PM -0200, Eduardo Lima (Etrunko) wrote: > On 01/13/2012 03:19 AM, Daniel Veillard wrote: > > On Fri, Jan 13, 2012 at 09:45:47AM +0800, Wayne Xia wrote: > >> ? 2012-1-13 7:16, Sharad Mishra ??: > >>> << snip>> > >>> > >>>> diff --git a/libnetwork/libbridge/libbridge.h b/libnetwork/ > >>>> libbridge/libbridge.h > >>>> new file mode 100644 > >>>> index 0000000..39964f2 > >>>> --- /dev/null > >>>> +++ b/libnetwork/libbridge/libbridge.h > >>>> @@ -0,0 +1,119 @@ > >>>> +/* > >>>> + * Copyright (C) 2000 Lennert Buytenhek > >>> > >>> Are you using an existing code written by above author? > >>> If it is a new code then use - > >>> > >> codes in this patch are existing ones have no modification by me, I > >> wonder whether moving source codes of these into libvirt-cim project > >> is acceptable. > > > > In general that's not a good idea. > > The problem is that if there is a security problem we need to fix the > > original package and all the copies which were done in various projects. > > Also such copied code tend to not be updated, makes it easier to bypass > > APIs boundaries and becomes long term maintenance problems. > > So unless said code is kind of confidential, i.e. not widely distributed > > then that something to avoid really, > > > > Daniel > > > > Also there is an issue with license. Libvirt-cim is LGPL while the code > you copied is GPL. In this case all files that make use of those > features should be relicensed as GPL as well. > > While I have no experience on this area, I guess it would be not receive > the legal approval in the end. Yeah, that's sounds like the biggest problem :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel at veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/ From xiawenc at linux.vnet.ibm.com Mon Jan 16 06:52:10 2012 From: xiawenc at linux.vnet.ibm.com (Wayne Xia) Date: Mon, 16 Jan 2012 14:52:10 +0800 Subject: [Libvirt-cim] [V3 PATCH 01/10] add source code of libbridge and libnl-3 In-Reply-To: <20120116023510.GL3609@redhat.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> <1326361614-18674-2-git-send-email-xiawenc@linux.vnet.ibm.com> <4F0F8CCB.1050207@linux.vnet.ibm.com> <20120113051940.GI3609@redhat.com> <4F107197.5070507@linux.vnet.ibm.com> <20120116023510.GL3609@redhat.com> Message-ID: <4F13C91A.1010206@linux.vnet.ibm.com> ? 2012-1-16 10:35, Daniel Veillard ??: > On Fri, Jan 13, 2012 at 04:01:59PM -0200, Eduardo Lima (Etrunko) wrote: >> On 01/13/2012 03:19 AM, Daniel Veillard wrote: >>> On Fri, Jan 13, 2012 at 09:45:47AM +0800, Wayne Xia wrote: >>>> ? 2012-1-13 7:16, Sharad Mishra ??: >>>>> << snip>> >>>>> >>>>>> diff --git a/libnetwork/libbridge/libbridge.h b/libnetwork/ >>>>>> libbridge/libbridge.h >>>>>> new file mode 100644 >>>>>> index 0000000..39964f2 >>>>>> --- /dev/null >>>>>> +++ b/libnetwork/libbridge/libbridge.h >>>>>> @@ -0,0 +1,119 @@ >>>>>> +/* >>>>>> + * Copyright (C) 2000 Lennert Buytenhek >>>>> >>>>> Are you using an existing code written by above author? >>>>> If it is a new code then use - >>>>> >>>> codes in this patch are existing ones have no modification by me, I >>>> wonder whether moving source codes of these into libvirt-cim project >>>> is acceptable. >>> >>> In general that's not a good idea. >>> The problem is that if there is a security problem we need to fix the >>> original package and all the copies which were done in various projects. >>> Also such copied code tend to not be updated, makes it easier to bypass >>> APIs boundaries and becomes long term maintenance problems. >>> So unless said code is kind of confidential, i.e. not widely distributed >>> then that something to avoid really, >>> >>> Daniel >>> >> >> Also there is an issue with license. Libvirt-cim is LGPL while the code >> you copied is GPL. In this case all files that make use of those >> features should be relicensed as GPL as well. >> >> While I have no experience on this area, I guess it would be not receive >> the legal approval in the end. > > Yeah, that's sounds like the biggest problem :-) > Could I use .la and .a (static library) from libnl3 and libbridge project, and include the header files and link the static libaray? I guess this could walk around the license problem. (no source file added to this project). > Daniel > -- Best Regards Wayne Xia mail:xiawenc at linux.vnet.ibm.com tel:86-010-82450803 From cvincent at linux.vnet.ibm.com Tue Jan 17 16:31:09 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Tue, 17 Jan 2012 11:31:09 -0500 Subject: [Libvirt-cim] [PATCH v3 00/10] VLAN extension - ReadOnly functions In-Reply-To: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <4F15A24D.4040206@linux.vnet.ibm.com> Just a nit: The copyrights at the top of source files you've written should now be 2012. I'm in the process of a deeper review of the rest of the code and will respond soon. On 01/12/2012 04:46 AM, Wayne Xia wrote: > These patches would try introduce 4 class with readonly functionality. > It used libnl-3 and libbridge as static libarary as an implemention. > Program libnetwork_test would be generated under ./libnetwork/.libs/ . > Testing: > wbemcli -nl ein http://[]:[]@localhost:5988/root/virt:Net_VirtualEthernetSwitchSystem > wbemcli -nl ein http://[]:[]@localhost:5988/root/virt:Net_VirtualEthernetSwitchSystemSettingData > wbemcli -nl ein http://[]:[]@localhost:5988/root/virt:Net_EthernetPort > wbemcli -nl ein http://[]:[]@localhost:5988/root/virt:Net_EthernetPortAllocationSettingData > try with command vconfig and brctl modifying the system. > Note: > These patch only applys on libvirt-cim-0.5.15, Will try move it to 0.6.0 > with libvirt 0.9.4 on RH6 on v4 patch. > > repository: > git://gitorious.org/~xiaxia347/libvirt-cim/xiaxia347s-xiawenc.git > branch vlan_v3 > https://gitorious.org/libvirt-cim/xiaxia347s-xiawenc/trees/vlan_v3 > > > Wayne Xia (10): > add source code of libbridge and libnl-3 > building system modification for libnl3 and libbridge > building system of libnetwork linking with libnl3 and libbridge > libnetwork source code with a test program > add a CIM model helper in libxkutil > CIM model - Makefile change > CIM model - VESS > CIM model - VESSSD > CIM model - EthernetPort > CIM model - EASD > > Makefile.am | 14 +- > configure.ac | 19 +- > libnetwork/Makefile.am | 39 + > libnetwork/dll_magic.h | 13 + > libnetwork/host_network_API.c | 30 + > libnetwork/host_network_API.h | 25 + > libnetwork/host_network_basic.c | 657 ++++++ > libnetwork/host_network_basic.h | 170 ++ > libnetwork/host_network_error.h | 31 + > libnetwork/host_network_helper.c | 659 ++++++ > libnetwork/host_network_helper.h | 202 ++ > libnetwork/host_network_implement_OSAPI.c | 453 ++++ > libnetwork/host_network_implement_OSAPI.h | 21 + > libnetwork/libbridge/.gitignore | 2 + > libnetwork/libbridge/Makefile.am | 20 + > libnetwork/libbridge/libbridge.h | 119 + > libnetwork/libbridge/libbridge_devif.c | 442 ++++ > libnetwork/libbridge/libbridge_if.c | 117 + > libnetwork/libbridge/libbridge_init.c | 213 ++ > libnetwork/libbridge/libbridge_misc.c | 51 + > libnetwork/libbridge/libbridge_private.h | 56 + > libnetwork/libnetwork_test.c | 82 + > libnetwork/libnl3/Makefile.am | 8 + > libnetwork/libnl3/include/Makefile.am | 122 + > libnetwork/libnl3/include/linux/fib_rules.h | 69 + > libnetwork/libnl3/include/linux/gen_stats.h | 67 + > libnetwork/libnl3/include/linux/genetlink.h | 83 + > libnetwork/libnl3/include/linux/if.h | 140 ++ > libnetwork/libnl3/include/linux/if_addr.h | 55 + > libnetwork/libnl3/include/linux/if_arp.h | 156 ++ > libnetwork/libnl3/include/linux/if_ether.h | 125 ++ > libnetwork/libnl3/include/linux/if_link.h | 377 ++++ > libnetwork/libnl3/include/linux/if_vlan.h | 62 + > libnetwork/libnl3/include/linux/inetdevice.h | 36 + > libnetwork/libnl3/include/linux/ip_mp_alg.h | 22 + > libnetwork/libnl3/include/linux/ipv6.h | 146 ++ > libnetwork/libnl3/include/linux/neighbour.h | 155 ++ > libnetwork/libnl3/include/linux/netfilter.h | 57 + > .../libnl3/include/linux/netfilter/nfnetlink.h | 60 + > .../include/linux/netfilter/nfnetlink_conntrack.h | 140 ++ > .../libnl3/include/linux/netfilter/nfnetlink_log.h | 97 + > .../include/linux/netfilter/nfnetlink_queue.h | 94 + > libnetwork/libnl3/include/linux/netlink.h | 149 ++ > libnetwork/libnl3/include/linux/pkt_cls.h | 467 ++++ > libnetwork/libnl3/include/linux/pkt_sched.h | 606 +++++ > libnetwork/libnl3/include/linux/rtnetlink.h | 605 +++++ > libnetwork/libnl3/include/linux/snmp.h | 270 +++ > .../libnl3/include/linux/tc_ematch/tc_em_meta.h | 89 + > libnetwork/libnl3/include/netlink-generic.h | 20 + > libnetwork/libnl3/include/netlink-local.h | 213 ++ > libnetwork/libnl3/include/netlink-tc.h | 55 + > libnetwork/libnl3/include/netlink-types.h | 846 +++++++ > libnetwork/libnl3/include/netlink/addr.h | 66 + > libnetwork/libnl3/include/netlink/attr.h | 283 +++ > libnetwork/libnl3/include/netlink/cache-api.h | 230 ++ > libnetwork/libnl3/include/netlink/cache.h | 134 ++ > libnetwork/libnl3/include/netlink/cli/addr.h | 32 + > libnetwork/libnl3/include/netlink/cli/class.h | 21 + > libnetwork/libnl3/include/netlink/cli/cls.h | 24 + > libnetwork/libnl3/include/netlink/cli/ct.h | 34 + > libnetwork/libnl3/include/netlink/cli/link.h | 30 + > libnetwork/libnl3/include/netlink/cli/neigh.h | 27 + > libnetwork/libnl3/include/netlink/cli/qdisc.h | 23 + > libnetwork/libnl3/include/netlink/cli/route.h | 34 + > libnetwork/libnl3/include/netlink/cli/rule.h | 21 + > libnetwork/libnl3/include/netlink/cli/tc.h | 39 + > libnetwork/libnl3/include/netlink/cli/utils.h | 82 + > libnetwork/libnl3/include/netlink/data.h | 41 + > libnetwork/libnl3/include/netlink/errno.h | 64 + > .../libnl3/include/netlink/fib_lookup/lookup.h | 42 + > .../libnl3/include/netlink/fib_lookup/request.h | 51 + > libnetwork/libnl3/include/netlink/genl/ctrl.h | 40 + > libnetwork/libnl3/include/netlink/genl/family.h | 53 + > libnetwork/libnl3/include/netlink/genl/genl.h | 46 + > libnetwork/libnl3/include/netlink/genl/mngt.h | 87 + > libnetwork/libnl3/include/netlink/handlers.h | 146 ++ > libnetwork/libnl3/include/netlink/list.h | 93 + > libnetwork/libnl3/include/netlink/msg.h | 147 ++ > libnetwork/libnl3/include/netlink/netfilter/ct.h | 126 ++ > libnetwork/libnl3/include/netlink/netfilter/log.h | 109 + > .../libnl3/include/netlink/netfilter/log_msg.h | 98 + > .../libnl3/include/netlink/netfilter/netfilter.h | 31 + > libnetwork/libnl3/include/netlink/netfilter/nfnl.h | 44 + > .../libnl3/include/netlink/netfilter/queue.h | 90 + > .../libnl3/include/netlink/netfilter/queue_msg.h | 104 + > libnetwork/libnl3/include/netlink/netlink-compat.h | 50 + > libnetwork/libnl3/include/netlink/netlink-kernel.h | 293 +++ > libnetwork/libnl3/include/netlink/netlink.h | 93 + > libnetwork/libnl3/include/netlink/object-api.h | 348 +++ > libnetwork/libnl3/include/netlink/object.h | 70 + > libnetwork/libnl3/include/netlink/route/addr.h | 98 + > libnetwork/libnl3/include/netlink/route/class.h | 66 + > .../libnl3/include/netlink/route/classifier.h | 51 + > .../libnl3/include/netlink/route/cls/basic.h | 31 + > .../libnl3/include/netlink/route/cls/cgroup.h | 30 + > .../libnl3/include/netlink/route/cls/ematch.h | 95 + > .../libnl3/include/netlink/route/cls/ematch/cmp.h | 32 + > .../libnl3/include/netlink/route/cls/ematch/meta.h | 41 + > .../include/netlink/route/cls/ematch/nbyte.h | 36 + > .../libnl3/include/netlink/route/cls/ematch/text.h | 42 + > libnetwork/libnl3/include/netlink/route/cls/fw.h | 29 + > .../libnl3/include/netlink/route/cls/police.h | 29 + > libnetwork/libnl3/include/netlink/route/cls/u32.h | 43 + > libnetwork/libnl3/include/netlink/route/link.h | 217 ++ > libnetwork/libnl3/include/netlink/route/link/api.h | 134 ++ > .../libnl3/include/netlink/route/link/bonding.h | 37 + > .../libnl3/include/netlink/route/link/inet.h | 29 + > .../libnl3/include/netlink/route/link/info-api.h | 20 + > .../libnl3/include/netlink/route/link/vlan.h | 57 + > .../libnl3/include/netlink/route/neighbour.h | 79 + > libnetwork/libnl3/include/netlink/route/neightbl.h | 65 + > libnetwork/libnl3/include/netlink/route/nexthop.h | 65 + > libnetwork/libnl3/include/netlink/route/pktloc.h | 49 + > libnetwork/libnl3/include/netlink/route/qdisc.h | 73 + > .../libnl3/include/netlink/route/qdisc/cbq.h | 30 + > .../libnl3/include/netlink/route/qdisc/dsmark.h | 41 + > .../libnl3/include/netlink/route/qdisc/fifo.h | 28 + > .../libnl3/include/netlink/route/qdisc/htb.h | 47 + > .../libnl3/include/netlink/route/qdisc/netem.h | 75 + > .../libnl3/include/netlink/route/qdisc/prio.h | 53 + > .../libnl3/include/netlink/route/qdisc/red.h | 17 + > .../libnl3/include/netlink/route/qdisc/sfq.h | 36 + > .../libnl3/include/netlink/route/qdisc/tbf.h | 40 + > libnetwork/libnl3/include/netlink/route/route.h | 124 + > libnetwork/libnl3/include/netlink/route/rtnl.h | 69 + > libnetwork/libnl3/include/netlink/route/rule.h | 75 + > libnetwork/libnl3/include/netlink/route/tc-api.h | 143 ++ > libnetwork/libnl3/include/netlink/route/tc.h | 105 + > libnetwork/libnl3/include/netlink/socket.h | 69 + > libnetwork/libnl3/include/netlink/types.h | 110 + > libnetwork/libnl3/include/netlink/utils.h | 85 + > libnetwork/libnl3/include/netlink/version.h | 28 + > libnetwork/libnl3/include/netlink/version.h.in | 28 + > libnetwork/libnl3/lib/Makefile.am | 99 + > libnetwork/libnl3/lib/addr.c | 918 ++++++++ > libnetwork/libnl3/lib/attr.c | 1213 ++++++++++ > libnetwork/libnl3/lib/cache.c | 965 ++++++++ > libnetwork/libnl3/lib/cache_mngr.c | 391 ++++ > libnetwork/libnl3/lib/cache_mngt.c | 256 +++ > libnetwork/libnl3/lib/cli/cls/basic.c | 93 + > libnetwork/libnl3/lib/cli/cls/cgroup.c | 75 + > libnetwork/libnl3/lib/cli/qdisc/bfifo.c | 83 + > libnetwork/libnl3/lib/cli/qdisc/blackhole.c | 64 + > libnetwork/libnl3/lib/cli/qdisc/htb.c | 203 ++ > libnetwork/libnl3/lib/cli/qdisc/pfifo.c | 77 + > libnetwork/libnl3/lib/data.c | 186 ++ > libnetwork/libnl3/lib/defs.h | 85 + > libnetwork/libnl3/lib/defs.h.in | 84 + > libnetwork/libnl3/lib/error.c | 116 + > libnetwork/libnl3/lib/fib_lookup/lookup.c | 348 +++ > libnetwork/libnl3/lib/fib_lookup/request.c | 185 ++ > libnetwork/libnl3/lib/genl/ctrl.c | 380 ++++ > libnetwork/libnl3/lib/genl/family.c | 316 +++ > libnetwork/libnl3/lib/genl/genl.c | 268 +++ > libnetwork/libnl3/lib/genl/mngt.c | 273 +++ > libnetwork/libnl3/lib/handlers.c | 395 ++++ > libnetwork/libnl3/lib/msg.c | 1050 +++++++++ > libnetwork/libnl3/lib/netfilter/ct.c | 601 +++++ > libnetwork/libnl3/lib/netfilter/ct_obj.c | 785 +++++++ > libnetwork/libnl3/lib/netfilter/log.c | 251 +++ > libnetwork/libnl3/lib/netfilter/log_msg.c | 209 ++ > libnetwork/libnl3/lib/netfilter/log_msg_obj.c | 458 ++++ > libnetwork/libnl3/lib/netfilter/log_obj.c | 287 +++ > libnetwork/libnl3/lib/netfilter/netfilter.c | 53 + > libnetwork/libnl3/lib/netfilter/nfnl.c | 245 ++ > libnetwork/libnl3/lib/netfilter/queue.c | 251 +++ > libnetwork/libnl3/lib/netfilter/queue_msg.c | 284 +++ > libnetwork/libnl3/lib/netfilter/queue_msg_obj.c | 492 ++++ > libnetwork/libnl3/lib/netfilter/queue_obj.c | 215 ++ > libnetwork/libnl3/lib/nl.c | 896 ++++++++ > libnetwork/libnl3/lib/object.c | 395 ++++ > libnetwork/libnl3/lib/route/addr.c | 1054 +++++++++ > libnetwork/libnl3/lib/route/class.c | 473 ++++ > libnetwork/libnl3/lib/route/classid.c | 441 ++++ > libnetwork/libnl3/lib/route/cls.c | 441 ++++ > libnetwork/libnl3/lib/route/cls/basic.c | 229 ++ > libnetwork/libnl3/lib/route/cls/cgroup.c | 189 ++ > libnetwork/libnl3/lib/route/cls/ematch.c | 701 ++++++ > libnetwork/libnl3/lib/route/cls/ematch/cmp.c | 93 + > libnetwork/libnl3/lib/route/cls/ematch/container.c | 41 + > libnetwork/libnl3/lib/route/cls/ematch/meta.c | 334 +++ > libnetwork/libnl3/lib/route/cls/ematch/nbyte.c | 139 ++ > libnetwork/libnl3/lib/route/cls/ematch/text.c | 183 ++ > libnetwork/libnl3/lib/route/cls/ematch_grammar.l | 162 ++ > libnetwork/libnl3/lib/route/cls/ematch_syntax.y | 497 +++++ > libnetwork/libnl3/lib/route/cls/fw.c | 190 ++ > libnetwork/libnl3/lib/route/cls/police.c | 66 + > libnetwork/libnl3/lib/route/cls/u32.c | 551 +++++ > libnetwork/libnl3/lib/route/link.c | 2342 ++++++++++++++++++++ > libnetwork/libnl3/lib/route/link/api.c | 316 +++ > libnetwork/libnl3/lib/route/link/bonding.c | 217 ++ > libnetwork/libnl3/lib/route/link/bridge.c | 83 + > libnetwork/libnl3/lib/route/link/dummy.c | 40 + > libnetwork/libnl3/lib/route/link/inet.c | 280 +++ > libnetwork/libnl3/lib/route/link/inet6.c | 377 ++++ > libnetwork/libnl3/lib/route/link/vlan.c | 565 +++++ > libnetwork/libnl3/lib/route/neigh.c | 846 +++++++ > libnetwork/libnl3/lib/route/neightbl.c | 815 +++++++ > libnetwork/libnl3/lib/route/nexthop.c | 290 +++ > libnetwork/libnl3/lib/route/pktloc.c | 260 +++ > libnetwork/libnl3/lib/route/pktloc_grammar.l | 51 + > libnetwork/libnl3/lib/route/pktloc_syntax.y | 103 + > libnetwork/libnl3/lib/route/qdisc.c | 575 +++++ > libnetwork/libnl3/lib/route/qdisc/blackhole.c | 37 + > libnetwork/libnl3/lib/route/qdisc/cbq.c | 204 ++ > libnetwork/libnl3/lib/route/qdisc/dsmark.c | 413 ++++ > libnetwork/libnl3/lib/route/qdisc/fifo.c | 169 ++ > libnetwork/libnl3/lib/route/qdisc/htb.c | 643 ++++++ > libnetwork/libnl3/lib/route/qdisc/netem.c | 906 ++++++++ > libnetwork/libnl3/lib/route/qdisc/prio.c | 294 +++ > libnetwork/libnl3/lib/route/qdisc/red.c | 190 ++ > libnetwork/libnl3/lib/route/qdisc/sfq.c | 256 +++ > libnetwork/libnl3/lib/route/qdisc/tbf.c | 460 ++++ > libnetwork/libnl3/lib/route/route.c | 202 ++ > libnetwork/libnl3/lib/route/route_obj.c | 1148 ++++++++++ > libnetwork/libnl3/lib/route/route_utils.c | 171 ++ > libnetwork/libnl3/lib/route/rtnl.c | 124 + > libnetwork/libnl3/lib/route/rule.c | 753 +++++++ > libnetwork/libnl3/lib/route/tc.c | 1069 +++++++++ > libnetwork/libnl3/lib/socket.c | 628 ++++++ > libnetwork/libnl3/lib/stamp-h1 | 1 + > libnetwork/libnl3/lib/utils.c | 1040 +++++++++ > libxkutil/Makefile.am | 12 +- > libxkutil/network_model_helper.c | 466 ++++ > libxkutil/network_model_helper.h | 105 + > schema/EthernetPort.mof | 4 + > schema/EthernetPort.registration | 3 + > schema/EthernetPortAllocationSettingData.mof | 21 + > .../EthernetPortAllocationSettingData.registration | 3 + > schema/VirtualEthernetSwitchSystem.mof | 10 + > schema/VirtualEthernetSwitchSystem.registration | 3 + > schema/VirtualEthernetSwitchSystemSettingData.mof | 27 + > ...ualEthernetSwitchSystemSettingData.registration | 3 + > src/Makefile.am | 23 +- > src/Virt_EASD.c | 729 ++++++ > src/Virt_EASD.h | 59 + > src/Virt_EthernetPort.c | 561 +++++ > src/Virt_EthernetPort.h | 58 + > src/Virt_VESSSD.c | 372 ++++ > src/Virt_VESSSD.h | 39 + > src/Virt_VirtualEthernetSwitchSystem.c | 477 ++++ > src/Virt_VirtualEthernetSwitchSystem.h | 52 + > 242 files changed, 53037 insertions(+), 10 deletions(-) > create mode 100644 libnetwork/Makefile.am > create mode 100644 libnetwork/dll_magic.h > create mode 100644 libnetwork/host_network_API.c > create mode 100644 libnetwork/host_network_API.h > create mode 100644 libnetwork/host_network_basic.c > create mode 100644 libnetwork/host_network_basic.h > create mode 100644 libnetwork/host_network_error.h > create mode 100644 libnetwork/host_network_helper.c > create mode 100644 libnetwork/host_network_helper.h > create mode 100644 libnetwork/host_network_implement_OSAPI.c > create mode 100644 libnetwork/host_network_implement_OSAPI.h > create mode 100755 libnetwork/libbridge/.gitignore > create mode 100644 libnetwork/libbridge/Makefile.am > create mode 100644 libnetwork/libbridge/libbridge.h > create mode 100644 libnetwork/libbridge/libbridge_devif.c > create mode 100644 libnetwork/libbridge/libbridge_if.c > create mode 100644 libnetwork/libbridge/libbridge_init.c > create mode 100644 libnetwork/libbridge/libbridge_misc.c > create mode 100644 libnetwork/libbridge/libbridge_private.h > create mode 100644 libnetwork/libnetwork_test.c > create mode 100644 libnetwork/libnl3/Makefile.am > create mode 100644 libnetwork/libnl3/include/Makefile.am > create mode 100644 libnetwork/libnl3/include/linux/fib_rules.h > create mode 100644 libnetwork/libnl3/include/linux/gen_stats.h > create mode 100644 libnetwork/libnl3/include/linux/genetlink.h > create mode 100644 libnetwork/libnl3/include/linux/if.h > create mode 100644 libnetwork/libnl3/include/linux/if_addr.h > create mode 100644 libnetwork/libnl3/include/linux/if_arp.h > create mode 100644 libnetwork/libnl3/include/linux/if_ether.h > create mode 100644 libnetwork/libnl3/include/linux/if_link.h > create mode 100644 libnetwork/libnl3/include/linux/if_vlan.h > create mode 100644 libnetwork/libnl3/include/linux/inetdevice.h > create mode 100644 libnetwork/libnl3/include/linux/ip_mp_alg.h > create mode 100644 libnetwork/libnl3/include/linux/ipv6.h > create mode 100644 libnetwork/libnl3/include/linux/neighbour.h > create mode 100644 libnetwork/libnl3/include/linux/netfilter.h > create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink.h > create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink_conntrack.h > create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink_log.h > create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink_queue.h > create mode 100644 libnetwork/libnl3/include/linux/netlink.h > create mode 100644 libnetwork/libnl3/include/linux/pkt_cls.h > create mode 100644 libnetwork/libnl3/include/linux/pkt_sched.h > create mode 100644 libnetwork/libnl3/include/linux/rtnetlink.h > create mode 100644 libnetwork/libnl3/include/linux/snmp.h > create mode 100644 libnetwork/libnl3/include/linux/tc_ematch/tc_em_meta.h > create mode 100644 libnetwork/libnl3/include/netlink-generic.h > create mode 100644 libnetwork/libnl3/include/netlink-local.h > create mode 100644 libnetwork/libnl3/include/netlink-tc.h > create mode 100644 libnetwork/libnl3/include/netlink-types.h > create mode 100644 libnetwork/libnl3/include/netlink/addr.h > create mode 100644 libnetwork/libnl3/include/netlink/attr.h > create mode 100644 libnetwork/libnl3/include/netlink/cache-api.h > create mode 100644 libnetwork/libnl3/include/netlink/cache.h > create mode 100644 libnetwork/libnl3/include/netlink/cli/addr.h > create mode 100644 libnetwork/libnl3/include/netlink/cli/class.h > create mode 100644 libnetwork/libnl3/include/netlink/cli/cls.h > create mode 100644 libnetwork/libnl3/include/netlink/cli/ct.h > create mode 100644 libnetwork/libnl3/include/netlink/cli/link.h > create mode 100644 libnetwork/libnl3/include/netlink/cli/neigh.h > create mode 100644 libnetwork/libnl3/include/netlink/cli/qdisc.h > create mode 100644 libnetwork/libnl3/include/netlink/cli/route.h > create mode 100644 libnetwork/libnl3/include/netlink/cli/rule.h > create mode 100644 libnetwork/libnl3/include/netlink/cli/tc.h > create mode 100644 libnetwork/libnl3/include/netlink/cli/utils.h > create mode 100644 libnetwork/libnl3/include/netlink/data.h > create mode 100644 libnetwork/libnl3/include/netlink/errno.h > create mode 100644 libnetwork/libnl3/include/netlink/fib_lookup/lookup.h > create mode 100644 libnetwork/libnl3/include/netlink/fib_lookup/request.h > create mode 100644 libnetwork/libnl3/include/netlink/genl/ctrl.h > create mode 100644 libnetwork/libnl3/include/netlink/genl/family.h > create mode 100644 libnetwork/libnl3/include/netlink/genl/genl.h > create mode 100644 libnetwork/libnl3/include/netlink/genl/mngt.h > create mode 100644 libnetwork/libnl3/include/netlink/handlers.h > create mode 100644 libnetwork/libnl3/include/netlink/list.h > create mode 100644 libnetwork/libnl3/include/netlink/msg.h > create mode 100644 libnetwork/libnl3/include/netlink/netfilter/ct.h > create mode 100644 libnetwork/libnl3/include/netlink/netfilter/log.h > create mode 100644 libnetwork/libnl3/include/netlink/netfilter/log_msg.h > create mode 100644 libnetwork/libnl3/include/netlink/netfilter/netfilter.h > create mode 100644 libnetwork/libnl3/include/netlink/netfilter/nfnl.h > create mode 100644 libnetwork/libnl3/include/netlink/netfilter/queue.h > create mode 100644 libnetwork/libnl3/include/netlink/netfilter/queue_msg.h > create mode 100644 libnetwork/libnl3/include/netlink/netlink-compat.h > create mode 100644 libnetwork/libnl3/include/netlink/netlink-kernel.h > create mode 100644 libnetwork/libnl3/include/netlink/netlink.h > create mode 100644 libnetwork/libnl3/include/netlink/object-api.h > create mode 100644 libnetwork/libnl3/include/netlink/object.h > create mode 100644 libnetwork/libnl3/include/netlink/route/addr.h > create mode 100644 libnetwork/libnl3/include/netlink/route/class.h > create mode 100644 libnetwork/libnl3/include/netlink/route/classifier.h > create mode 100644 libnetwork/libnl3/include/netlink/route/cls/basic.h > create mode 100644 libnetwork/libnl3/include/netlink/route/cls/cgroup.h > create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch.h > create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch/cmp.h > create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch/meta.h > create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch/nbyte.h > create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch/text.h > create mode 100644 libnetwork/libnl3/include/netlink/route/cls/fw.h > create mode 100644 libnetwork/libnl3/include/netlink/route/cls/police.h > create mode 100644 libnetwork/libnl3/include/netlink/route/cls/u32.h > create mode 100644 libnetwork/libnl3/include/netlink/route/link.h > create mode 100644 libnetwork/libnl3/include/netlink/route/link/api.h > create mode 100644 libnetwork/libnl3/include/netlink/route/link/bonding.h > create mode 100644 libnetwork/libnl3/include/netlink/route/link/inet.h > create mode 100644 libnetwork/libnl3/include/netlink/route/link/info-api.h > create mode 100644 libnetwork/libnl3/include/netlink/route/link/vlan.h > create mode 100644 libnetwork/libnl3/include/netlink/route/neighbour.h > create mode 100644 libnetwork/libnl3/include/netlink/route/neightbl.h > create mode 100644 libnetwork/libnl3/include/netlink/route/nexthop.h > create mode 100644 libnetwork/libnl3/include/netlink/route/pktloc.h > create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc.h > create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/cbq.h > create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/dsmark.h > create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/fifo.h > create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/htb.h > create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/netem.h > create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/prio.h > create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/red.h > create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/sfq.h > create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/tbf.h > create mode 100644 libnetwork/libnl3/include/netlink/route/route.h > create mode 100644 libnetwork/libnl3/include/netlink/route/rtnl.h > create mode 100644 libnetwork/libnl3/include/netlink/route/rule.h > create mode 100644 libnetwork/libnl3/include/netlink/route/tc-api.h > create mode 100644 libnetwork/libnl3/include/netlink/route/tc.h > create mode 100644 libnetwork/libnl3/include/netlink/socket.h > create mode 100644 libnetwork/libnl3/include/netlink/types.h > create mode 100644 libnetwork/libnl3/include/netlink/utils.h > create mode 100644 libnetwork/libnl3/include/netlink/version.h > create mode 100644 libnetwork/libnl3/include/netlink/version.h.in > create mode 100644 libnetwork/libnl3/lib/Makefile.am > create mode 100644 libnetwork/libnl3/lib/addr.c > create mode 100644 libnetwork/libnl3/lib/attr.c > create mode 100644 libnetwork/libnl3/lib/cache.c > create mode 100644 libnetwork/libnl3/lib/cache_mngr.c > create mode 100644 libnetwork/libnl3/lib/cache_mngt.c > create mode 100644 libnetwork/libnl3/lib/cli/cls/.dirstamp > create mode 100644 libnetwork/libnl3/lib/cli/cls/basic.c > create mode 100644 libnetwork/libnl3/lib/cli/cls/cgroup.c > create mode 100644 libnetwork/libnl3/lib/cli/qdisc/.dirstamp > create mode 100644 libnetwork/libnl3/lib/cli/qdisc/bfifo.c > create mode 100644 libnetwork/libnl3/lib/cli/qdisc/blackhole.c > create mode 100644 libnetwork/libnl3/lib/cli/qdisc/htb.c > create mode 100644 libnetwork/libnl3/lib/cli/qdisc/pfifo.c > create mode 100644 libnetwork/libnl3/lib/data.c > create mode 100644 libnetwork/libnl3/lib/defs.h > create mode 100644 libnetwork/libnl3/lib/defs.h.in > create mode 100644 libnetwork/libnl3/lib/error.c > create mode 100644 libnetwork/libnl3/lib/fib_lookup/.dirstamp > create mode 100644 libnetwork/libnl3/lib/fib_lookup/lookup.c > create mode 100644 libnetwork/libnl3/lib/fib_lookup/request.c > create mode 100644 libnetwork/libnl3/lib/genl/.dirstamp > create mode 100644 libnetwork/libnl3/lib/genl/ctrl.c > create mode 100644 libnetwork/libnl3/lib/genl/family.c > create mode 100644 libnetwork/libnl3/lib/genl/genl.c > create mode 100644 libnetwork/libnl3/lib/genl/mngt.c > create mode 100644 libnetwork/libnl3/lib/handlers.c > create mode 100644 libnetwork/libnl3/lib/msg.c > create mode 100644 libnetwork/libnl3/lib/netfilter/.dirstamp > create mode 100644 libnetwork/libnl3/lib/netfilter/ct.c > create mode 100644 libnetwork/libnl3/lib/netfilter/ct_obj.c > create mode 100644 libnetwork/libnl3/lib/netfilter/log.c > create mode 100644 libnetwork/libnl3/lib/netfilter/log_msg.c > create mode 100644 libnetwork/libnl3/lib/netfilter/log_msg_obj.c > create mode 100644 libnetwork/libnl3/lib/netfilter/log_obj.c > create mode 100644 libnetwork/libnl3/lib/netfilter/netfilter.c > create mode 100644 libnetwork/libnl3/lib/netfilter/nfnl.c > create mode 100644 libnetwork/libnl3/lib/netfilter/queue.c > create mode 100644 libnetwork/libnl3/lib/netfilter/queue_msg.c > create mode 100644 libnetwork/libnl3/lib/netfilter/queue_msg_obj.c > create mode 100644 libnetwork/libnl3/lib/netfilter/queue_obj.c > create mode 100644 libnetwork/libnl3/lib/nl.c > create mode 100644 libnetwork/libnl3/lib/object.c > create mode 100644 libnetwork/libnl3/lib/route/.dirstamp > create mode 100644 libnetwork/libnl3/lib/route/addr.c > create mode 100644 libnetwork/libnl3/lib/route/class.c > create mode 100644 libnetwork/libnl3/lib/route/classid.c > create mode 100644 libnetwork/libnl3/lib/route/cls.c > create mode 100644 libnetwork/libnl3/lib/route/cls/.dirstamp > create mode 100644 libnetwork/libnl3/lib/route/cls/basic.c > create mode 100644 libnetwork/libnl3/lib/route/cls/cgroup.c > create mode 100644 libnetwork/libnl3/lib/route/cls/ematch.c > create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/.dirstamp > create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/cmp.c > create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/container.c > create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/meta.c > create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/nbyte.c > create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/text.c > create mode 100644 libnetwork/libnl3/lib/route/cls/ematch_grammar.l > create mode 100644 libnetwork/libnl3/lib/route/cls/ematch_syntax.y > create mode 100644 libnetwork/libnl3/lib/route/cls/fw.c > create mode 100644 libnetwork/libnl3/lib/route/cls/police.c > create mode 100644 libnetwork/libnl3/lib/route/cls/u32.c > create mode 100644 libnetwork/libnl3/lib/route/link.c > create mode 100644 libnetwork/libnl3/lib/route/link/.dirstamp > create mode 100644 libnetwork/libnl3/lib/route/link/api.c > create mode 100644 libnetwork/libnl3/lib/route/link/bonding.c > create mode 100644 libnetwork/libnl3/lib/route/link/bridge.c > create mode 100644 libnetwork/libnl3/lib/route/link/dummy.c > create mode 100644 libnetwork/libnl3/lib/route/link/inet.c > create mode 100644 libnetwork/libnl3/lib/route/link/inet6.c > create mode 100644 libnetwork/libnl3/lib/route/link/vlan.c > create mode 100644 libnetwork/libnl3/lib/route/neigh.c > create mode 100644 libnetwork/libnl3/lib/route/neightbl.c > create mode 100644 libnetwork/libnl3/lib/route/nexthop.c > create mode 100644 libnetwork/libnl3/lib/route/pktloc.c > create mode 100644 libnetwork/libnl3/lib/route/pktloc_grammar.l > create mode 100644 libnetwork/libnl3/lib/route/pktloc_syntax.y > create mode 100644 libnetwork/libnl3/lib/route/qdisc.c > create mode 100644 libnetwork/libnl3/lib/route/qdisc/.dirstamp > create mode 100644 libnetwork/libnl3/lib/route/qdisc/blackhole.c > create mode 100644 libnetwork/libnl3/lib/route/qdisc/cbq.c > create mode 100644 libnetwork/libnl3/lib/route/qdisc/dsmark.c > create mode 100644 libnetwork/libnl3/lib/route/qdisc/fifo.c > create mode 100644 libnetwork/libnl3/lib/route/qdisc/htb.c > create mode 100644 libnetwork/libnl3/lib/route/qdisc/netem.c > create mode 100644 libnetwork/libnl3/lib/route/qdisc/prio.c > create mode 100644 libnetwork/libnl3/lib/route/qdisc/red.c > create mode 100644 libnetwork/libnl3/lib/route/qdisc/sfq.c > create mode 100644 libnetwork/libnl3/lib/route/qdisc/tbf.c > create mode 100644 libnetwork/libnl3/lib/route/route.c > create mode 100644 libnetwork/libnl3/lib/route/route_obj.c > create mode 100644 libnetwork/libnl3/lib/route/route_utils.c > create mode 100644 libnetwork/libnl3/lib/route/rtnl.c > create mode 100644 libnetwork/libnl3/lib/route/rule.c > create mode 100644 libnetwork/libnl3/lib/route/tc.c > create mode 100644 libnetwork/libnl3/lib/socket.c > create mode 100644 libnetwork/libnl3/lib/stamp-h1 > create mode 100644 libnetwork/libnl3/lib/utils.c > create mode 100644 libxkutil/network_model_helper.c > create mode 100644 libxkutil/network_model_helper.h > create mode 100644 schema/EthernetPort.mof > create mode 100644 schema/EthernetPort.registration > create mode 100644 schema/EthernetPortAllocationSettingData.mof > create mode 100644 schema/EthernetPortAllocationSettingData.registration > create mode 100644 schema/VirtualEthernetSwitchSystem.mof > create mode 100644 schema/VirtualEthernetSwitchSystem.registration > create mode 100644 schema/VirtualEthernetSwitchSystemSettingData.mof > create mode 100644 schema/VirtualEthernetSwitchSystemSettingData.registration > create mode 100644 src/Virt_EASD.c > create mode 100644 src/Virt_EASD.h > create mode 100644 src/Virt_EthernetPort.c > create mode 100644 src/Virt_EthernetPort.h > create mode 100644 src/Virt_VESSSD.c > create mode 100644 src/Virt_VESSSD.h > create mode 100644 src/Virt_VirtualEthernetSwitchSystem.c > create mode 100644 src/Virt_VirtualEthernetSwitchSystem.h > -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From eblima at linux.vnet.ibm.com Tue Jan 17 16:58:17 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 17 Jan 2012 14:58:17 -0200 Subject: [Libvirt-cim] [PATCH] autoconfiscate.sh: Use proper command for revision count Message-ID: <1326819497-30936-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- autoconfiscate.sh | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/autoconfiscate.sh b/autoconfiscate.sh index 8ea8a30..f0ef048 100755 --- a/autoconfiscate.sh +++ b/autoconfiscate.sh @@ -19,7 +19,7 @@ autoconf --force && if test -x $(which git); then git rev-parse --short HEAD > .changeset - git log | grep "^commit" | wc -l > .revision + git rev-list --count HEAD > .revision else echo "Unknown" > .changeset echo "0" > .revision -- 1.7.7.5 From eblima at linux.vnet.ibm.com Tue Jan 17 17:01:45 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 17 Jan 2012 15:01:45 -0200 Subject: [Libvirt-cim] [PATCH] [TEST] Update revision and changeset info Message-ID: <1326819705-31213-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" We are now using git (yay!!). Port the commands from mercurial to the git equivalents. Signed-off-by: Eduardo Lima (Etrunko) --- suites/libvirt-cim/lib/XenKvmLib/reporting.py | 6 ++---- 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/suites/libvirt-cim/lib/XenKvmLib/reporting.py b/suites/libvirt-cim/lib/XenKvmLib/reporting.py index b6df36e..67ec974 100644 --- a/suites/libvirt-cim/lib/XenKvmLib/reporting.py +++ b/suites/libvirt-cim/lib/XenKvmLib/reporting.py @@ -33,10 +33,8 @@ def get_cmd_val(cmd, ip): return out def get_cimtest_version(): - revision = commands.getoutput("hg parents --template \ - \"{rev}\" 2>/dev/null") - changeset = commands.getoutput("hg parents --template \ - \"{node|short}\" 2>/dev/null") + revision = commands.getoutput("git rev-list --count HEAD 2>/dev/null") + changeset = commands.getoutput("git rev-parse --short HEAD 2> /dev/null") return revision, changeset def get_libvirt_ver(ip): -- 1.7.7.5 From eblima at linux.vnet.ibm.com Tue Jan 17 17:03:17 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 17 Jan 2012 15:03:17 -0200 Subject: [Libvirt-cim] [PATCH] [TEST] Add .gitignore Message-ID: <1326819797-31378-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- .gitignore | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf5ec57 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.log +*.pyc +*.pyo +run_report.txt -- 1.7.7.5 From cvincent at linux.vnet.ibm.com Tue Jan 17 17:06:41 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Tue, 17 Jan 2012 12:06:41 -0500 Subject: [Libvirt-cim] [PATCH] autoconfiscate.sh: Use proper command for revision count In-Reply-To: <1326819497-30936-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326819497-30936-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F15AAA1.9000501@linux.vnet.ibm.com> I like this better than the current hack, but the syntax does not seems correct. On RHEL 6.2: $ git rev-list --count HEAD usage: git rev-list [OPTION] ... [ -- paths... ] limiting output: --max-count=nr --max-age=epoch --min-age=epoch --sparse --no-merges --remove-empty --all --branches --tags --remotes --stdin --quiet ordering output: --topo-order --date-order --reverse formatting output: --parents --children --objects | --objects-edge --unpacked --header | --pretty --abbrev=nr | --no-abbrev --abbrev-commit --left-right special purpose: --bisect --bisect-vars --bisect-all On 01/17/2012 11:58 AM, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > Signed-off-by: Eduardo Lima (Etrunko) > --- > autoconfiscate.sh | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/autoconfiscate.sh b/autoconfiscate.sh > index 8ea8a30..f0ef048 100755 > --- a/autoconfiscate.sh > +++ b/autoconfiscate.sh > @@ -19,7 +19,7 @@ autoconf --force&& > > if test -x $(which git); then > git rev-parse --short HEAD> .changeset > - git log | grep "^commit" | wc -l> .revision > + git rev-list --count HEAD> .revision > else > echo "Unknown"> .changeset > echo "0"> .revision -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From eblima at linux.vnet.ibm.com Tue Jan 17 17:28:44 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 17 Jan 2012 15:28:44 -0200 Subject: [Libvirt-cim] [PATCH] autoconfiscate.sh: Use proper command for revision count In-Reply-To: <4F15AAA1.9000501@linux.vnet.ibm.com> References: <1326819497-30936-1-git-send-email-eblima@linux.vnet.ibm.com> <4F15AAA1.9000501@linux.vnet.ibm.com> Message-ID: <4F15AFCC.1020802@linux.vnet.ibm.com> On 01/17/2012 03:06 PM, Chip Vincent wrote: > I like this better than the current hack, but the syntax does not seems > correct. On RHEL 6.2: So it seems git in RHEL is quite old. I don't know when it was added but you can use git rev-list HEAD | wc -l in this case. Can you check with "git rev-list --help" if it includes the --count option? Best regards, Etrunko -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Tue Jan 17 19:24:21 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 17 Jan 2012 17:24:21 -0200 Subject: [Libvirt-cim] [PATCH 1/2] libxkutil: Linked list helper In-Reply-To: <1326828262-8166-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326828262-8166-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1326828262-8166-2-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/Makefile.am | 48 +++++++--- libxkutil/list_util.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++++ libxkutil/list_util.h | 76 ++++++++++++++++ 3 files changed, 341 insertions(+), 14 deletions(-) create mode 100644 libxkutil/list_util.c create mode 100644 libxkutil/list_util.h diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am index f1adc03..fe1d6de 100644 --- a/libxkutil/Makefile.am +++ b/libxkutil/Makefile.am @@ -1,21 +1,41 @@ # Copyright IBM Corp. 2007 +AM_CFLAGS = \ + $(CFLAGS_STRICT) \ + -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" -AM_CFLAGS = $(CFLAGS_STRICT) \ - -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" +noinst_HEADERS = \ + cs_util.h \ + misc_util.h \ + device_parsing.h \ + xmlgen.h \ + infostore.h \ + pool_parsing.h \ + acl_parsing.h \ + list_util.h -noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ - pool_parsing.h acl_parsing.h +lib_LTLIBRARIES = \ + libxkutil.la -lib_LTLIBRARIES = libxkutil.la +libxkutil_la_SOURCES = \ + cs_util_instance.c \ + misc_util.c \ + device_parsing.c \ + xmlgen.c \ + infostore.c \ + pool_parsing.c \ + acl_parsing.c \ + list_util.c -libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ - xmlgen.c infostore.c pool_parsing.c acl_parsing.c -libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ -libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ - @LIBUUID_LIBS@ +libxkutil_la_LIBADD = \ + @LIBVIRT_LIBS@ \ + @LIBUUID_LIBS@ -noinst_PROGRAMS = xml_parse_test +noinst_PROGRAMS = \ + xml_parse_test -xml_parse_test_SOURCES = xml_parse_test.c -xml_parse_test_LDADD = libxkutil.la \ - @LIBVIRT_LIBS@ +xml_parse_test_SOURCES = \ + xml_parse_test.c + +xml_parse_test_LDADD = \ + libxkutil.la \ + @LIBVIRT_LIBS@ diff --git a/libxkutil/list_util.c b/libxkutil/list_util.c new file mode 100644 index 0000000..9f14aeb --- /dev/null +++ b/libxkutil/list_util.c @@ -0,0 +1,231 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Eduardo Lima (Etrunko) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "list_util.h" + +struct _list_node_t { + list_node_t *prev; + list_node_t *next; + void *data; +}; + +list_t *list_new(list_data_free_cb free_cb, list_data_cmp_cb cmp_cb) +{ + list_t *l = calloc(1, sizeof(*l)); + if (l == NULL) + return NULL; + + l->free_cb = free_cb; + l->cmp_cb = cmp_cb; + return l; +} + +void list_free(list_t *list) +{ + list_node_t *n; + + if (list == NULL || list->head == NULL) + return; + + n = list->head; + + do { + if (list->free_cb) + list->free_cb(n->data); + + n = n->next; + free(n->prev); + } while (n != list->head); + + free(list); +} + +void list_append(list_t *list, void *data) +{ + list_node_t *n; + + if (list == NULL) + return; + + n = calloc(1, sizeof(*n)); + + if (n == NULL) + return; + + n->data = data; + + if (list->head == NULL) { /* empty list */ + n->next = n->prev = n; + list->head = n; + goto end; + } + + n->next = list->head; + n->prev = list->head->prev; + + list->head->prev->next = n; + list->head->prev = n; + + end: + list->count += 1; +} + +void list_prepend(list_t *list, void *data) +{ + list_append(list, data); + list->head = list->head->prev; +} + +void *list_find(list_t *list, void *user_data) +{ + list_node_t *n = list_find_node(list, user_data); + return list_node_data_get(n); +} + +list_node_t *list_find_node(list_t *list, void *user_data) +{ + list_node_t *n; + + if (list == NULL || list->head == NULL || list->cmp_cb == NULL) + return NULL; + + n = list->head; + do { + if (list->cmp_cb(n->data, user_data) == 0) + return n; + + n = n->next; + } while (n != list->head); + + return NULL; +} + +void list_remove(list_t *list, void *data) +{ + list_node_t *n = list_find_node(list, data); + list_remove_node(list, n); +} + +void list_remove_node(list_t *list, list_node_t *node) +{ + if (list == NULL || list->head == NULL || node == NULL) + return; + + if (node->next == node) { /* only 1 item */ + list->head = NULL; + } else { + if (node == list->head) /* first node */ + list->head = node->next; + + node->prev->next = node->next; + node->next->prev = node->prev; + } + + if (list->free_cb) + list->free_cb(node->data); + + free(node); + list->count -= 1; +} + +void list_foreach(list_t *list, list_foreach_cb cb, void *user_data) +{ + list_node_t *node; + + if (list == NULL || list->head == NULL) + return; + + node = list->head; + do { + cb(node->data, user_data); + node = node->next; + } while (node != list->head); +} + +void *list_node_data_get(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->data; +} + +void list_node_data_set(list_node_t *node, void *data) +{ + if (node == NULL) + return; + + node->data = data; +} + +void *list_first(list_t *list) +{ + return list_node_data_get(list->head); +} + +list_node_t *list_first_node(list_t *list) +{ + return list->head; +} + +void *list_last(list_t *list) +{ + return list_node_data_get(list_last_node(list)); +} + +list_node_t *list_last_node(list_t *list) +{ + if (list == NULL) + return NULL; + + return list->head->prev; +} + +void *list_node_next(list_node_t *node) +{ + return list_node_data_get(list_node_next_node(node)); +} + +list_node_t *list_node_next_node(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->next; +} + +void *list_node_prev(list_node_t *node) +{ + return list_node_data_get(list_node_prev_node(node)); +} + +list_node_t *list_node_prev_node(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->prev; +} diff --git a/libxkutil/list_util.h b/libxkutil/list_util.h new file mode 100644 index 0000000..96c0338 --- /dev/null +++ b/libxkutil/list_util.h @@ -0,0 +1,76 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Eduardo Lima (Etrunko) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LIST_UTIL_H +#define __LIST_UTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _list_node_t list_node_t; + +typedef void (*list_data_free_cb)(void *data); +typedef int (*list_data_cmp_cb)(void *list_data, void *user_data); +typedef void (*list_foreach_cb)(void *list_data, void *user_data); + +typedef struct _list_t list_t; +struct _list_t { + int count; + list_node_t *head; + list_data_free_cb free_cb; + list_data_cmp_cb cmp_cb; +}; + +list_t *list_new(list_data_free_cb free_cb, list_data_cmp_cb cmp_cb); +void list_free(list_t *list); + +void list_append(list_t *list, void *data); +void list_prepend(list_t *list, void *data); + +void *list_find(list_t *list, void *user_data); +list_node_t *list_find_node(list_t *list, void *user_data); + +void list_remove(list_t *list, void *data); +void list_remove_node(list_t *list, list_node_t *node); + +void list_foreach(list_t *list, list_foreach_cb cb, void *user_data); + +inline void *list_node_data_get(list_node_t *node); +inline void list_node_data_set(list_node_t *node, void *data); + +inline void *list_first(list_t *list); +inline list_node_t *list_first_node(list_t *list); + +inline void *list_last(list_t *list); +inline list_node_t *list_last_node(list_t *list); + +inline void *list_node_next(list_node_t *node); +inline list_node_t *list_node_next_node(list_node_t *node); + +inline void *list_node_prev(list_node_t *node); +inline list_node_t *list_node_prev_node(list_node_t *node); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __LIST_UTIL_H */ -- 1.7.7.5 From eblima at linux.vnet.ibm.com Tue Jan 17 19:24:22 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 17 Jan 2012 17:24:22 -0200 Subject: [Libvirt-cim] [PATCH 2/2] CSI: Use list helper implementation In-Reply-To: <1326828262-8166-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326828262-8166-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1326828262-8166-3-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- src/Virt_ComputerSystemIndication.c | 95 ++++++++++------------------------- 1 files changed, 26 insertions(+), 69 deletions(-) diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c index eb1a71c..ed1c48d 100644 --- a/src/Virt_ComputerSystemIndication.c +++ b/src/Virt_ComputerSystemIndication.c @@ -19,6 +19,10 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #include #include @@ -34,11 +38,11 @@ #include #include -#include #include -#include -#include "config.h" +#include +#include +#include #include "Virt_ComputerSystem.h" #include "Virt_ComputerSystemIndication.h" @@ -64,8 +68,6 @@ struct _csi_dom_xml_t { char uuid[VIR_UUID_STRING_BUFLEN]; char *name; char *xml; - csi_dom_xml_t *next; - csi_dom_xml_t *prev; }; typedef struct _csi_thread_data_t csi_thread_data_t; @@ -73,7 +75,7 @@ struct _csi_thread_data_t { CMPI_THREAD_TYPE id; int active_filters; int dom_count; - csi_dom_xml_t *dom_list; + list_t *dom_list; struct ind_args *args; }; @@ -83,15 +85,24 @@ static bool lifecycle_enabled = false; static csi_thread_data_t csi_thread_data[CSI_NUM_PLATFORMS] = {{0}, {0}, {0}}; /* - * Domain list manipulation + * Domain manipulation */ -static void csi_dom_xml_free(csi_dom_xml_t *dom) +static void csi_dom_xml_free(void *data) { + csi_dom_xml_t *dom = (csi_dom_xml_t *) data; free(dom->xml); free(dom->name); free(dom); } +static int csi_dom_xml_cmp(void *data, void *cmp_cb_data) +{ + csi_dom_xml_t *dom = (csi_dom_xml_t *) data; + const char *uuid = (const char *) cmp_cb_data; + + return strcmp(dom->uuid, uuid); +} + static int csi_dom_xml_set(csi_dom_xml_t *dom, virDomainPtr dom_ptr, CMPIStatus *s) { const char *name; @@ -149,65 +160,10 @@ static csi_dom_xml_t *csi_dom_xml_new(virDomainPtr dom_ptr, CMPIStatus *s) static void csi_thread_dom_list_append(csi_thread_data_t *thread, csi_dom_xml_t *dom) { - /* empty list */ - if (thread->dom_list == NULL) { - dom->next = dom->prev = dom; - thread->dom_list = dom; - goto end; - } - - dom->next = thread->dom_list; - dom->prev = thread->dom_list->prev; - - thread->dom_list->prev->next = dom; - thread->dom_list->prev = dom; - - end: - thread->dom_count += 1; -} - -static csi_dom_xml_t *csi_thread_dom_list_find(csi_thread_data_t *thread, - const char *uuid) -{ - csi_dom_xml_t *dom; - if (thread->dom_list == NULL) - return NULL; - - dom = thread->dom_list; - - do { - if (STREQ(dom->uuid, uuid)) - return dom; - - dom = dom->next; - } while (dom != thread->dom_list); + thread->dom_list = list_new(csi_dom_xml_free, csi_dom_xml_cmp); - return NULL; -} - -static void csi_thread_dom_list_remove(csi_thread_data_t *thread, - csi_dom_xml_t *dom) -{ - if (dom->next == dom) { /* Only one node */ - thread->dom_list = NULL; - } else { - if (thread->dom_list == dom) /* First node */ - thread->dom_list = dom->next; - - dom->prev->next = dom->next; - dom->next->prev = dom->prev; - } - - thread->dom_count -= 1; - - csi_dom_xml_free(dom); -} - -static void csi_thread_dom_list_free(csi_thread_data_t *thread) -{ - while(thread->dom_list != NULL) - csi_thread_dom_list_remove(thread, thread->dom_list); + list_append(thread->dom_list, dom); } static void csi_free_thread_data(void *data) @@ -217,7 +173,8 @@ static void csi_free_thread_data(void *data) if (data == NULL) return; - csi_thread_dom_list_free(thread); + list_free(thread->dom_list); + thread->dom_list = NULL; stdi_free_ind_args(&thread->args); } @@ -511,7 +468,7 @@ static int update_domain_list(virConnectPtr conn, csi_thread_data_t *thread) CMPIStatus s = {CMPI_RC_OK, NULL}; int i, count; - csi_thread_dom_list_free(thread); + list_free(thread->dom_list); count = get_domain_list(conn, &dom_ptr_list); @@ -573,7 +530,7 @@ static int csi_domain_event_cb(virConnectPtr conn, if (cs_event != CS_CREATED) { char uuid[VIR_UUID_STRING_BUFLEN] = {0}; virDomainGetUUIDString(dom, &uuid[0]); - dom_xml = csi_thread_dom_list_find(thread, uuid); + dom_xml = list_find(thread->dom_list, uuid); } if (dom_xml == NULL) { @@ -594,7 +551,7 @@ static int csi_domain_event_cb(virConnectPtr conn, } } else if (event == VIR_DOMAIN_EVENT_DEFINED && detail == VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) { - csi_thread_dom_list_remove(thread, dom_xml); + list_remove(thread->dom_list, dom_xml); } end: -- 1.7.7.5 From eblima at linux.vnet.ibm.com Tue Jan 17 19:24:20 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 17 Jan 2012 17:24:20 -0200 Subject: [Libvirt-cim] [PATCH 0/2] Implementation of a linked list helper Message-ID: <1326828262-8166-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" This series provides a generic linked list implementation for libxkutil that is based on the one originally developed for the libvirt domain events support recently integrated upstream. As test case I ported the ComputerSystemIndication provider code to use this list implementation. In the near future it will be also used by the event loop that I am currently working on to allow systems with libvirt older than 0.9.0 to make use of the same feature. Other possible use cases would be to port the code of libxkutil/*_parsing* to also use the list implementation instead of static arrays. -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com Eduardo Lima (Etrunko) (2): libxkutil: Linked list helper CSI: Use list helper implementation libxkutil/Makefile.am | 48 +++++-- libxkutil/list_util.c | 231 +++++++++++++++++++++++++++++++++++ libxkutil/list_util.h | 76 ++++++++++++ src/Virt_ComputerSystemIndication.c | 95 ++++----------- 4 files changed, 367 insertions(+), 83 deletions(-) create mode 100644 libxkutil/list_util.c create mode 100644 libxkutil/list_util.h -- 1.7.7.5 From eblima at linux.vnet.ibm.com Tue Jan 17 19:37:38 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 17 Jan 2012 17:37:38 -0200 Subject: [Libvirt-cim] [PATCH 1/2] libxkutil: Linked list helper In-Reply-To: <1326828262-8166-2-git-send-email-eblima@linux.vnet.ibm.com> References: <1326828262-8166-1-git-send-email-eblima@linux.vnet.ibm.com> <1326828262-8166-2-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F15CE02.1000407@linux.vnet.ibm.com> On 01/17/2012 05:24 PM, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > Signed-off-by: Eduardo Lima (Etrunko) > --- > libxkutil/Makefile.am | 48 +++++++--- > libxkutil/list_util.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++++ > libxkutil/list_util.h | 76 ++++++++++++++++ > 3 files changed, 341 insertions(+), 14 deletions(-) > create mode 100644 libxkutil/list_util.c > create mode 100644 libxkutil/list_util.h > > diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am > index f1adc03..fe1d6de 100644 > --- a/libxkutil/Makefile.am > +++ b/libxkutil/Makefile.am > @@ -1,21 +1,41 @@ > # Copyright IBM Corp. 2007 > +AM_CFLAGS = \ > + $(CFLAGS_STRICT) \ > + -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" > > -AM_CFLAGS = $(CFLAGS_STRICT) \ > - -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" > +noinst_HEADERS = \ > + cs_util.h \ > + misc_util.h \ > + device_parsing.h \ > + xmlgen.h \ > + infostore.h \ > + pool_parsing.h \ > + acl_parsing.h \ > + list_util.h > > -noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ > - pool_parsing.h acl_parsing.h > +lib_LTLIBRARIES = \ > + libxkutil.la > > -lib_LTLIBRARIES = libxkutil.la > +libxkutil_la_SOURCES = \ > + cs_util_instance.c \ > + misc_util.c \ > + device_parsing.c \ > + xmlgen.c \ > + infostore.c \ > + pool_parsing.c \ > + acl_parsing.c \ > + list_util.c > > -libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ > - xmlgen.c infostore.c pool_parsing.c acl_parsing.c > -libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ > -libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ > - @LIBUUID_LIBS@ > +libxkutil_la_LIBADD = \ > + @LIBVIRT_LIBS@ \ > + @LIBUUID_LIBS@ > Oooops, I screwed it with LDFLAGS here. Sending a new version right now. -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Tue Jan 17 19:45:24 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 17 Jan 2012 17:45:24 -0200 Subject: [Libvirt-cim] [PATCH 1/2] libxkutil: Linked list helper In-Reply-To: <1326829525-32612-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326829525-32612-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1326829525-32612-2-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/Makefile.am | 51 ++++++++--- libxkutil/list_util.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++++ libxkutil/list_util.h | 76 ++++++++++++++++ 3 files changed, 344 insertions(+), 14 deletions(-) create mode 100644 libxkutil/list_util.c create mode 100644 libxkutil/list_util.h diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am index f1adc03..8d436ad 100644 --- a/libxkutil/Makefile.am +++ b/libxkutil/Makefile.am @@ -1,21 +1,44 @@ # Copyright IBM Corp. 2007 +AM_CFLAGS = \ + $(CFLAGS_STRICT) \ + -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" -AM_CFLAGS = $(CFLAGS_STRICT) \ - -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" +noinst_HEADERS = \ + cs_util.h \ + misc_util.h \ + device_parsing.h \ + xmlgen.h \ + infostore.h \ + pool_parsing.h \ + acl_parsing.h \ + list_util.h -noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ - pool_parsing.h acl_parsing.h +lib_LTLIBRARIES = \ + libxkutil.la -lib_LTLIBRARIES = libxkutil.la +libxkutil_la_SOURCES = \ + cs_util_instance.c \ + misc_util.c \ + device_parsing.c \ + xmlgen.c \ + infostore.c \ + pool_parsing.c \ + acl_parsing.c \ + list_util.c -libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ - xmlgen.c infostore.c pool_parsing.c acl_parsing.c -libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ -libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ - @LIBUUID_LIBS@ +libxkutil_la_LDFLAGS = \ + -version-info @VERSION_INFO@ -noinst_PROGRAMS = xml_parse_test +libxkutil_la_LIBADD = \ + @LIBVIRT_LIBS@ \ + @LIBUUID_LIBS@ -xml_parse_test_SOURCES = xml_parse_test.c -xml_parse_test_LDADD = libxkutil.la \ - @LIBVIRT_LIBS@ +noinst_PROGRAMS = \ + xml_parse_test + +xml_parse_test_SOURCES = \ + xml_parse_test.c + +xml_parse_test_LDADD = \ + libxkutil.la \ + @LIBVIRT_LIBS@ diff --git a/libxkutil/list_util.c b/libxkutil/list_util.c new file mode 100644 index 0000000..9f14aeb --- /dev/null +++ b/libxkutil/list_util.c @@ -0,0 +1,231 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Eduardo Lima (Etrunko) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "list_util.h" + +struct _list_node_t { + list_node_t *prev; + list_node_t *next; + void *data; +}; + +list_t *list_new(list_data_free_cb free_cb, list_data_cmp_cb cmp_cb) +{ + list_t *l = calloc(1, sizeof(*l)); + if (l == NULL) + return NULL; + + l->free_cb = free_cb; + l->cmp_cb = cmp_cb; + return l; +} + +void list_free(list_t *list) +{ + list_node_t *n; + + if (list == NULL || list->head == NULL) + return; + + n = list->head; + + do { + if (list->free_cb) + list->free_cb(n->data); + + n = n->next; + free(n->prev); + } while (n != list->head); + + free(list); +} + +void list_append(list_t *list, void *data) +{ + list_node_t *n; + + if (list == NULL) + return; + + n = calloc(1, sizeof(*n)); + + if (n == NULL) + return; + + n->data = data; + + if (list->head == NULL) { /* empty list */ + n->next = n->prev = n; + list->head = n; + goto end; + } + + n->next = list->head; + n->prev = list->head->prev; + + list->head->prev->next = n; + list->head->prev = n; + + end: + list->count += 1; +} + +void list_prepend(list_t *list, void *data) +{ + list_append(list, data); + list->head = list->head->prev; +} + +void *list_find(list_t *list, void *user_data) +{ + list_node_t *n = list_find_node(list, user_data); + return list_node_data_get(n); +} + +list_node_t *list_find_node(list_t *list, void *user_data) +{ + list_node_t *n; + + if (list == NULL || list->head == NULL || list->cmp_cb == NULL) + return NULL; + + n = list->head; + do { + if (list->cmp_cb(n->data, user_data) == 0) + return n; + + n = n->next; + } while (n != list->head); + + return NULL; +} + +void list_remove(list_t *list, void *data) +{ + list_node_t *n = list_find_node(list, data); + list_remove_node(list, n); +} + +void list_remove_node(list_t *list, list_node_t *node) +{ + if (list == NULL || list->head == NULL || node == NULL) + return; + + if (node->next == node) { /* only 1 item */ + list->head = NULL; + } else { + if (node == list->head) /* first node */ + list->head = node->next; + + node->prev->next = node->next; + node->next->prev = node->prev; + } + + if (list->free_cb) + list->free_cb(node->data); + + free(node); + list->count -= 1; +} + +void list_foreach(list_t *list, list_foreach_cb cb, void *user_data) +{ + list_node_t *node; + + if (list == NULL || list->head == NULL) + return; + + node = list->head; + do { + cb(node->data, user_data); + node = node->next; + } while (node != list->head); +} + +void *list_node_data_get(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->data; +} + +void list_node_data_set(list_node_t *node, void *data) +{ + if (node == NULL) + return; + + node->data = data; +} + +void *list_first(list_t *list) +{ + return list_node_data_get(list->head); +} + +list_node_t *list_first_node(list_t *list) +{ + return list->head; +} + +void *list_last(list_t *list) +{ + return list_node_data_get(list_last_node(list)); +} + +list_node_t *list_last_node(list_t *list) +{ + if (list == NULL) + return NULL; + + return list->head->prev; +} + +void *list_node_next(list_node_t *node) +{ + return list_node_data_get(list_node_next_node(node)); +} + +list_node_t *list_node_next_node(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->next; +} + +void *list_node_prev(list_node_t *node) +{ + return list_node_data_get(list_node_prev_node(node)); +} + +list_node_t *list_node_prev_node(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->prev; +} diff --git a/libxkutil/list_util.h b/libxkutil/list_util.h new file mode 100644 index 0000000..96c0338 --- /dev/null +++ b/libxkutil/list_util.h @@ -0,0 +1,76 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Eduardo Lima (Etrunko) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LIST_UTIL_H +#define __LIST_UTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _list_node_t list_node_t; + +typedef void (*list_data_free_cb)(void *data); +typedef int (*list_data_cmp_cb)(void *list_data, void *user_data); +typedef void (*list_foreach_cb)(void *list_data, void *user_data); + +typedef struct _list_t list_t; +struct _list_t { + int count; + list_node_t *head; + list_data_free_cb free_cb; + list_data_cmp_cb cmp_cb; +}; + +list_t *list_new(list_data_free_cb free_cb, list_data_cmp_cb cmp_cb); +void list_free(list_t *list); + +void list_append(list_t *list, void *data); +void list_prepend(list_t *list, void *data); + +void *list_find(list_t *list, void *user_data); +list_node_t *list_find_node(list_t *list, void *user_data); + +void list_remove(list_t *list, void *data); +void list_remove_node(list_t *list, list_node_t *node); + +void list_foreach(list_t *list, list_foreach_cb cb, void *user_data); + +inline void *list_node_data_get(list_node_t *node); +inline void list_node_data_set(list_node_t *node, void *data); + +inline void *list_first(list_t *list); +inline list_node_t *list_first_node(list_t *list); + +inline void *list_last(list_t *list); +inline list_node_t *list_last_node(list_t *list); + +inline void *list_node_next(list_node_t *node); +inline list_node_t *list_node_next_node(list_node_t *node); + +inline void *list_node_prev(list_node_t *node); +inline list_node_t *list_node_prev_node(list_node_t *node); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __LIST_UTIL_H */ -- 1.7.7.5 From eblima at linux.vnet.ibm.com Tue Jan 17 19:45:23 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 17 Jan 2012 17:45:23 -0200 Subject: [Libvirt-cim] [PATCH v2 0/2] Implementation of a linked list helper Message-ID: <1326829525-32612-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" This series provides a generic linked list implementation for libxkutil that is based on the one originally developed for the libvirt domain events support recently integrated upstream. As test case I ported the ComputerSystemIndication provider code to use this list implementation. In the near future it will be also used by the event loop that I am currently working on to allow systems with libvirt older than 0.9.0 to make use of the same feature. Other possible use cases would be to port the code of libxkutil/*_parsing* to also use the list implementation instead of static arrays. Changes from v1: - Fix version iformation in Makefile.am -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com Eduardo Lima (Etrunko) (2): libxkutil: Linked list helper CSI: Use list helper implementation libxkutil/Makefile.am | 51 ++++++-- libxkutil/list_util.c | 231 +++++++++++++++++++++++++++++++++++ libxkutil/list_util.h | 76 ++++++++++++ src/Virt_ComputerSystemIndication.c | 95 ++++----------- 4 files changed, 370 insertions(+), 83 deletions(-) create mode 100644 libxkutil/list_util.c create mode 100644 libxkutil/list_util.h -- 1.7.7.5 From eblima at linux.vnet.ibm.com Tue Jan 17 19:45:25 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 17 Jan 2012 17:45:25 -0200 Subject: [Libvirt-cim] [PATCH 2/2] CSI: Use list helper implementation In-Reply-To: <1326829525-32612-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326829525-32612-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1326829525-32612-3-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- src/Virt_ComputerSystemIndication.c | 95 ++++++++++------------------------- 1 files changed, 26 insertions(+), 69 deletions(-) diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c index eb1a71c..ed1c48d 100644 --- a/src/Virt_ComputerSystemIndication.c +++ b/src/Virt_ComputerSystemIndication.c @@ -19,6 +19,10 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #include #include @@ -34,11 +38,11 @@ #include #include -#include #include -#include -#include "config.h" +#include +#include +#include #include "Virt_ComputerSystem.h" #include "Virt_ComputerSystemIndication.h" @@ -64,8 +68,6 @@ struct _csi_dom_xml_t { char uuid[VIR_UUID_STRING_BUFLEN]; char *name; char *xml; - csi_dom_xml_t *next; - csi_dom_xml_t *prev; }; typedef struct _csi_thread_data_t csi_thread_data_t; @@ -73,7 +75,7 @@ struct _csi_thread_data_t { CMPI_THREAD_TYPE id; int active_filters; int dom_count; - csi_dom_xml_t *dom_list; + list_t *dom_list; struct ind_args *args; }; @@ -83,15 +85,24 @@ static bool lifecycle_enabled = false; static csi_thread_data_t csi_thread_data[CSI_NUM_PLATFORMS] = {{0}, {0}, {0}}; /* - * Domain list manipulation + * Domain manipulation */ -static void csi_dom_xml_free(csi_dom_xml_t *dom) +static void csi_dom_xml_free(void *data) { + csi_dom_xml_t *dom = (csi_dom_xml_t *) data; free(dom->xml); free(dom->name); free(dom); } +static int csi_dom_xml_cmp(void *data, void *cmp_cb_data) +{ + csi_dom_xml_t *dom = (csi_dom_xml_t *) data; + const char *uuid = (const char *) cmp_cb_data; + + return strcmp(dom->uuid, uuid); +} + static int csi_dom_xml_set(csi_dom_xml_t *dom, virDomainPtr dom_ptr, CMPIStatus *s) { const char *name; @@ -149,65 +160,10 @@ static csi_dom_xml_t *csi_dom_xml_new(virDomainPtr dom_ptr, CMPIStatus *s) static void csi_thread_dom_list_append(csi_thread_data_t *thread, csi_dom_xml_t *dom) { - /* empty list */ - if (thread->dom_list == NULL) { - dom->next = dom->prev = dom; - thread->dom_list = dom; - goto end; - } - - dom->next = thread->dom_list; - dom->prev = thread->dom_list->prev; - - thread->dom_list->prev->next = dom; - thread->dom_list->prev = dom; - - end: - thread->dom_count += 1; -} - -static csi_dom_xml_t *csi_thread_dom_list_find(csi_thread_data_t *thread, - const char *uuid) -{ - csi_dom_xml_t *dom; - if (thread->dom_list == NULL) - return NULL; - - dom = thread->dom_list; - - do { - if (STREQ(dom->uuid, uuid)) - return dom; - - dom = dom->next; - } while (dom != thread->dom_list); + thread->dom_list = list_new(csi_dom_xml_free, csi_dom_xml_cmp); - return NULL; -} - -static void csi_thread_dom_list_remove(csi_thread_data_t *thread, - csi_dom_xml_t *dom) -{ - if (dom->next == dom) { /* Only one node */ - thread->dom_list = NULL; - } else { - if (thread->dom_list == dom) /* First node */ - thread->dom_list = dom->next; - - dom->prev->next = dom->next; - dom->next->prev = dom->prev; - } - - thread->dom_count -= 1; - - csi_dom_xml_free(dom); -} - -static void csi_thread_dom_list_free(csi_thread_data_t *thread) -{ - while(thread->dom_list != NULL) - csi_thread_dom_list_remove(thread, thread->dom_list); + list_append(thread->dom_list, dom); } static void csi_free_thread_data(void *data) @@ -217,7 +173,8 @@ static void csi_free_thread_data(void *data) if (data == NULL) return; - csi_thread_dom_list_free(thread); + list_free(thread->dom_list); + thread->dom_list = NULL; stdi_free_ind_args(&thread->args); } @@ -511,7 +468,7 @@ static int update_domain_list(virConnectPtr conn, csi_thread_data_t *thread) CMPIStatus s = {CMPI_RC_OK, NULL}; int i, count; - csi_thread_dom_list_free(thread); + list_free(thread->dom_list); count = get_domain_list(conn, &dom_ptr_list); @@ -573,7 +530,7 @@ static int csi_domain_event_cb(virConnectPtr conn, if (cs_event != CS_CREATED) { char uuid[VIR_UUID_STRING_BUFLEN] = {0}; virDomainGetUUIDString(dom, &uuid[0]); - dom_xml = csi_thread_dom_list_find(thread, uuid); + dom_xml = list_find(thread->dom_list, uuid); } if (dom_xml == NULL) { @@ -594,7 +551,7 @@ static int csi_domain_event_cb(virConnectPtr conn, } } else if (event == VIR_DOMAIN_EVENT_DEFINED && detail == VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) { - csi_thread_dom_list_remove(thread, dom_xml); + list_remove(thread->dom_list, dom_xml); } end: -- 1.7.7.5 From snmishra at us.ibm.com Wed Jan 18 04:54:53 2012 From: snmishra at us.ibm.com (Sharad Mishra) Date: Tue, 17 Jan 2012 20:54:53 -0800 Subject: [Libvirt-cim] [PATCH 2/4] Fix possible memory leaks In-Reply-To: <1326480802-6035-3-git-send-email-eblima@linux.vnet.ibm.com> References: <1326480802-6035-1-git-send-email-eblima@linux.vnet.ibm.com> <1326480802-6035-3-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: libvirt-cim-bounces at redhat.com wrote on 01/13/2012 10:53:20 AM: > "Eduardo Lima (Etrunko)" > Sent by: libvirt-cim-bounces at redhat.com > > 01/13/12 10:53 AM > > Please respond to > List for discussion and development of libvirt CIM > > To > > libvirt-cim at redhat.com > > cc > > "Eduardo Lima \(Etrunko\)" > > Subject > > [Libvirt-cim] [PATCH 2/4] Fix possible memory leaks > > From: "Eduardo Lima (Etrunko)" > > As revealed by recent Coverity scan report provided by Red Hat: > https://bugzilla.redhat.com/show_bug.cgi?id=750418 > https://bugzilla.redhat.com/attachment.cgi?id=552325 > > Error: RESOURCE_LEAK: > pool_parsing.c:140: alloc_fn: Calling allocation function "realloc". > pool_parsing.c:140: var_assign: Assigning: "tmp" = storage returned > from "realloc(dev_paths, 8UL * (ct + 1U))". > pool_parsing.c:145: var_assign: Assigning: "dev_paths" = "tmp". > pool_parsing.c:149: leaked_storage: Variable "tmp" going out of > scope leaks the storage it points to. > pool_parsing.c:169: leaked_storage: Variable "dev_paths" going out > of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > xmlgen.c:891: alloc_fn: Calling allocation function "virt_device_dup". > device_parsing.c:873: alloc_fn: Storage is returned from allocation > function "calloc". > device_parsing.c:873: var_assign: Assigning: "dev" = "calloc(1UL, 152UL)". > device_parsing.c:928: return_alloc: Returning allocated memory "dev". > xmlgen.c:891: var_assign: Assigning: "dev" = storage returned from > "virt_device_dup(_dev)". > xmlgen.c:952: leaked_storage: Variable "dev" going out of scope > leaks the storage it points to. > > Error: RESOURCE_LEAK: > device_parsing.c:354: alloc_fn: Calling allocation function "calloc". > device_parsing.c:354: var_assign: Assigning: "vsi_dev" = storage > returned from "calloc(1UL, 56UL)". > device_parsing.c:385: noescape: Variable "vsi_dev" is not freed or > pointed-to in function "memcpy". > device_parsing.c:386: leaked_storage: Variable "vsi_dev" going out > of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_DevicePool.c:1077: alloc_arg: Calling allocation function > "get_diskpool_config" on "pools". > Virt_DevicePool.c:161: alloc_arg: "get_disk_parent" allocates memory > that is stored into "pools". > Virt_DevicePool.c:74: alloc_fn: Storage is returned from allocation > function "realloc". > Virt_DevicePool.c:74: var_assign: Assigning: "pools" = "realloc > (pools, (count + 1) * 24UL)". > Virt_DevicePool.c:86: var_assign: Assigning: "*_pools" = "pools". > Virt_DevicePool.c:163: var_assign: Assigning: "*_pools" = "pools". > Virt_DevicePool.c:1080: leaked_storage: Variable "pools" going out > of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_DevicePool.c:404: alloc_arg: Calling allocation function > "get_diskpool_config" on "pools". > Virt_DevicePool.c:161: alloc_arg: "get_disk_parent" allocates memory > that is stored into "pools". > Virt_DevicePool.c:74: alloc_fn: Storage is returned from allocation > function "realloc". > Virt_DevicePool.c:74: var_assign: Assigning: "pools" = "realloc > (pools, (count + 1) * 24UL)". > Virt_DevicePool.c:86: var_assign: Assigning: "*_pools" = "pools". > Virt_DevicePool.c:163: var_assign: Assigning: "*_pools" = "pools". > Virt_DevicePool.c:406: leaked_storage: Variable "pools" going out of > scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_VirtualSystemManagementService.c:415: alloc_fn: Calling > allocation function "realloc". > Virt_VirtualSystemManagementService.c:415: var_assign: Assigning: > "tmp_str_arr" = storage returned from "realloc > (domain->os_info.fv.bootlist, bl_size * 8UL)". > Virt_VirtualSystemManagementService.c:432: leaked_storage: Variable > "tmp_str_arr" going out of scope leaks the storage it points to. > Virt_VirtualSystemManagementService.c:440: leaked_storage: Variable > "tmp_str_arr" going out of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_VirtualSystemManagementService.c:2834: alloc_fn: Calling > allocation function "malloc". > Virt_VirtualSystemManagementService.c:2834: var_assign: Assigning: > "__retval" = storage returned from "malloc(__len)". > Virt_VirtualSystemManagementService.c:2834: noescape: Variable > "__retval" is not freed or pointed-to in function "memcpy". > Virt_VirtualSystemManagementService.c:2834: overwrite_var: > Overwriting "__retval" in call "__retval = (char *)memcpy(__retval, > "ResourceAllocationSettingDataCreatedIndication", __len)" leaks the > storage that "__retval" points to. > Virt_VirtualSystemManagementService.c:2834: var_assign: Assigning: > "__retval" = storage returned from "memcpy(__retval, > "ResourceAllocationSettingDataCreatedIndication", __len)". > Virt_VirtualSystemManagementService.c:2834: var_assign: Assigning: > "indication" = "__retval". > Virt_VirtualSystemManagementService.c:2901: leaked_storage: Variable > "indication" going out of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_VirtualSystemManagementService.c:2837: alloc_fn: Calling > allocation function "malloc". > Virt_VirtualSystemManagementService.c:2837: var_assign: Assigning: > "__retval" = storage returned from "malloc(__len)". > Virt_VirtualSystemManagementService.c:2837: noescape: Variable > "__retval" is not freed or pointed-to in function "memcpy". > Virt_VirtualSystemManagementService.c:2837: overwrite_var: > Overwriting "__retval" in call "__retval = (char *)memcpy(__retval, > "ResourceAllocationSettingDataDeletedIndication", __len)" leaks the > storage that "__retval" points to. > Virt_VirtualSystemManagementService.c:2837: var_assign: Assigning: > "__retval" = storage returned from "memcpy(__retval, > "ResourceAllocationSettingDataDeletedIndication", __len)". > Virt_VirtualSystemManagementService.c:2837: var_assign: Assigning: > "indication" = "__retval". > Virt_VirtualSystemManagementService.c:2901: leaked_storage: Variable > "indication" going out of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_VirtualSystemManagementService.c:2840: alloc_fn: Calling > allocation function "malloc". > Virt_VirtualSystemManagementService.c:2840: var_assign: Assigning: > "__retval" = storage returned from "malloc(__len)". > Virt_VirtualSystemManagementService.c:2840: noescape: Variable > "__retval" is not freed or pointed-to in function "memcpy". > Virt_VirtualSystemManagementService.c:2840: overwrite_var: > Overwriting "__retval" in call "__retval = (char *)memcpy(__retval, > "ResourceAllocationSettingDataModifiedIndication", __len)" leaks the > storage that "__retval" points to. > Virt_VirtualSystemManagementService.c:2840: var_assign: Assigning: > "__retval" = storage returned from "memcpy(__retval, > "ResourceAllocationSettingDataModifiedIndication", __len)". > Virt_VirtualSystemManagementService.c:2840: var_assign: Assigning: > "indication" = "__retval". > Virt_VirtualSystemManagementService.c:2901: leaked_storage: Variable > "indication" going out of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_AppliedFilterList.c:199: alloc_arg: Calling allocation function > "get_domain_list" on "doms". > cs_util_instance.c:52: alloc_fn: Storage is returned from allocation > function "calloc". > cs_util_instance.c:52: var_assign: Assigning: "list" = "calloc > (n_names + n_ids, 8UL)". > cs_util_instance.c:107: var_assign: Assigning: "*_list" = "list". > Virt_AppliedFilterList.c:251: leaked_storage: Variable "doms" going > out of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > misc_util.c:275: alloc_arg: Calling allocation function > "get_domain_list" on "list". > cs_util_instance.c:52: alloc_fn: Storage is returned from allocation > function "calloc". > cs_util_instance.c:52: var_assign: Assigning: "list" = "calloc > (n_names + n_ids, 8UL)". > cs_util_instance.c:107: var_assign: Assigning: "*_list" = "list". > misc_util.c:277: leaked_storage: Variable "list" going out of scope > leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_SwitchService.c:108: alloc_fn: Calling allocation function "popen". > Virt_SwitchService.c:108: var_assign: Assigning: "stream" = storage > returned from "popen(func, "r")". > Virt_SwitchService.c:118: noescape: Variable "stream" is not freed > or pointed-to in function "fgets". > Virt_SwitchService.c:131: leaked_storage: Variable "stream" going > out of scope leaks the storage it points to. > Virt_SwitchService.c:142: leaked_storage: Variable "stream" going > out of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_SwitchService.c:123: alloc_fn: Calling allocation function "realloc". > Virt_SwitchService.c:123: var_assign: Assigning: "tmp_list" = > storage returned from "realloc(arr, (i + 1) * 8UL)". > Virt_SwitchService.c:134: var_assign: Assigning: "arr" = "tmp_list". > Virt_SwitchService.c:142: leaked_storage: Variable "arr" going out > of scope leaks the storage it points to. > Virt_SwitchService.c:142: leaked_storage: Variable "tmp_list" going > out of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_SwitchService.c:236: alloc_fn: Calling allocation function "run_command". > Virt_SwitchService.c:123: alloc_fn: Storage is returned from > allocation function "realloc". > Virt_SwitchService.c:123: var_assign: Assigning: "tmp_list" = > "realloc(arr, (i + 1) * 8UL)". > Virt_SwitchService.c:134: var_assign: Assigning: "arr" = "tmp_list". > Virt_SwitchService.c:151: return_alloc: Returning allocated memory "arr". > Virt_SwitchService.c:236: var_assign: Assigning: "if_list" = > storage returned from "run_command("/sbin/ifconfig -a | /bin/grep > eth | /bin/awk \'{print$1}\'", &count, &s)". > /builddir/build/BUILD/libvirt-cim-0.6.0/src/Virt_SwitchService.c: > 269: leaked_storage: Variable "if_list" going out of scope leaks the > storage it points to. > > Signed-off-by: Eduardo Lima (Etrunko) > --- > libxkutil/cs_util_instance.c | 5 +++++ > libxkutil/device_parsing.c | 1 + > libxkutil/pool_parsing.c | 5 +++-- > libxkutil/xmlgen.c | 4 +++- > src/Virt_AppliedFilterList.c | 3 ++- > src/Virt_DevicePool.c | 5 ++++- > src/Virt_SwitchService.c | 24 +++++++++++++++++++ +---- > src/Virt_VirtualSystemManagementService.c | 14 +++++++------- > 8 files changed, 45 insertions(+), 16 deletions(-) > > diff --git a/libxkutil/cs_util_instance.c b/libxkutil/cs_util_instance.c > index d21f0ff..a383147 100644 > --- a/libxkutil/cs_util_instance.c > +++ b/libxkutil/cs_util_instance.c > @@ -104,6 +104,11 @@ int get_domain_list(virConnectPtr conn, > virDomainPtr **_list) > free(names); > free(ids); > > + if (idx == 0) { > + free(list); > + list = NULL; > + } > + > *_list = list; > > return idx; > diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c > index b0eccfc..a1e8d6c 100644 > --- a/libxkutil/device_parsing.c > +++ b/libxkutil/device_parsing.c > @@ -382,6 +382,7 @@ static int parse_vsi_device(xmlNode *dnode, > struct net_device *vdevs) > } > > memcpy(&(vdevs->vsi), vsi_dev, sizeof(*vsi_dev)); > + free(vsi_dev); > return 1; > > err: > diff --git a/libxkutil/pool_parsing.c b/libxkutil/pool_parsing.c > index f73b0fd..e41fc09 100644 > --- a/libxkutil/pool_parsing.c > +++ b/libxkutil/pool_parsing.c > @@ -163,10 +163,11 @@ static int parse_disk_source(xmlNode *node, > struct disk_pool *pool) > > pool->device_paths_ct = ct; > pool->device_paths = dev_paths; > + return 1; > > err: > - > - return 1; > + free(dev_paths); > + return 0; > } > > char *get_disk_pool_type(uint16_t type) > diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c > index 96b4e96..7fff4d1 100644 > --- a/libxkutil/xmlgen.c > +++ b/libxkutil/xmlgen.c > @@ -928,7 +928,6 @@ char *device_to_xml(struct virt_device *_dev) > dominfo->dev_input = dev; > break; > default: > - cleanup_virt_devices(&dev, 1); This change is causing FilterList -> 03_create.py to dump core. There are few others that are segfaulting. -Sharad > goto out; > } > > @@ -942,6 +941,9 @@ char *device_to_xml(struct virt_device *_dev) > out: > CU_DEBUG("Created Device XML:\n%s\n", xml); > > + if (dev != NULL) > + cleanup_virt_devices(&dev, 1); > + > cleanup_dominfo(&dominfo); > xmlFreeNode(root); > > diff --git a/src/Virt_AppliedFilterList.c b/src/Virt_AppliedFilterList.c > index 6567118..bc31c14 100644 > --- a/src/Virt_AppliedFilterList.c > +++ b/src/Virt_AppliedFilterList.c > @@ -197,7 +197,7 @@ static CMPIStatus list_to_net( > > /* get domains */ > dcount = get_domain_list(conn, &doms); > - if (dcount < 0) { > + if (dcount <= 0) { > cu_statusf(_BROKER, &s, > CMPI_RC_ERR_FAILED, > "Failed to get domain list"); > @@ -246,6 +246,7 @@ static CMPIStatus list_to_net( > } > > out: > + free(doms); > virConnectClose(conn); > > return s; > diff --git a/src/Virt_DevicePool.c b/src/Virt_DevicePool.c > index ab0baa0..fe5573f 100644 > --- a/src/Virt_DevicePool.c > +++ b/src/Virt_DevicePool.c > @@ -402,8 +402,10 @@ static char *_diskpool_member_of(virConnectPtr conn, > char *pool = NULL; > > count = get_diskpool_config(conn, &pools); > - if (count == 0) > + if (count == 0) { > + free(pools); > return NULL; > + } > > for (i = 0; i < count; i++) { > if (_diskpool_is_member(conn, &pools[i], file)) { > @@ -1091,6 +1093,7 @@ static CMPIStatus diskpool_instance(virConnectPtr conn, > count = get_diskpool_config(conn, &pools); > if ((id == NULL) && (count == 0)) { > CU_DEBUG("No defined DiskPools"); > + free(pools); > return s; > } > > diff --git a/src/Virt_SwitchService.c b/src/Virt_SwitchService.c > index 0d57f54..7e59d38 100644 > --- a/src/Virt_SwitchService.c > +++ b/src/Virt_SwitchService.c > @@ -128,20 +128,19 @@ static char **run_command(char *func, int > *len, CMPIStatus *s) { > cu_statusf(_BROKER, s, > CMPI_RC_ERR_NOT_FOUND, > "Failed to realloc"); > - return NULL; > + goto err; > } > > arr = tmp_list; > > - string = calloc(len, sizeof(char)); > + string = strndup(buff, len); > if (string == NULL) { > CU_DEBUG("Failed to allocate memory"); > cu_statusf(_BROKER, s, > CMPI_RC_ERR_NOT_FOUND, > "Failed to calloc"); > - return NULL; > + goto err; > } > - strncpy(string, buff, len); > arr[i] = string; > i++; > } > @@ -149,6 +148,19 @@ static char **run_command(char *func, int *len, > CMPIStatus *s) { > pclose(stream); > *len = i; > return arr; > + > + err: > + /* undo everything */ > + if (i > 0) { > + int count; > + for (count = 0; count < i; count++) > + free(arr[count]); > + } > + > + free(arr); > + pclose(stream); > + return NULL; > + > } > > static CMPIStatus set_inst_properties(const CMPIBroker *broker, > @@ -262,6 +274,10 @@ static CMPIStatus get_switchservice(const > CMPIObjectPath *reference, > CMSetProperty(inst, "IsVSISupported", (CMPIValue *)&vsi, > CMPI_boolean); > s.rc = CMPI_RC_OK; > > + for (i = 0; i < count; i++) > + free(if_list[i]); > + > + free(if_list); > out: > virConnectClose(conn); > *_inst = inst; > diff --git a/src/Virt_VirtualSystemManagementService.c b/src/ > Virt_VirtualSystemManagementService.c > index f8c5f24..3a0b423 100644 > --- a/src/Virt_VirtualSystemManagementService.c > +++ b/src/Virt_VirtualSystemManagementService.c > @@ -429,6 +429,7 @@ static int bootord_vssd_to_domain(CMPIInstance *inst, > > if (CMIsNullValue(boot_elem)) { > CU_DEBUG("Null BootDevice"); > + free(tmp_str_arr); > return 0; > } > > @@ -437,6 +438,7 @@ static int bootord_vssd_to_domain(CMPIInstance *inst, > if (str == NULL) { > CU_DEBUG("Could not extract char pointer from " > "CMPIArray"); > + free(tmp_str_arr); > return 0; > } > > @@ -2766,13 +2768,11 @@ static CMPIStatus _update_resources_for > (const CMPIContext *context, > } > > if (func == &resource_add) { > - indication = strdup(RASD_IND_CREATED); > - } > - else if (func == &resource_del) { > - indication = strdup(RASD_IND_DELETED); > - } > - else { > - indication = strdup(RASD_IND_MODIFIED); > + indication = RASD_IND_CREATED; > + } else if (func == &resource_del) { > + indication = RASD_IND_DELETED; > + } else { > + indication = RASD_IND_MODIFIED; > char *dummy_name = NULL; > > if (asprintf(&dummy_name, "%s/%s",dominfo->name, > devid) == -1) { > -- > 1.7.7.5 > > _______________________________________________ > Libvirt-cim mailing list > Libvirt-cim at redhat.com > https://www.redhat.com/mailman/listinfo/libvirt-cim > From xiawenc at linux.vnet.ibm.com Wed Jan 18 09:40:52 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Wed, 18 Jan 2012 17:40:52 +0800 Subject: [Libvirt-cim] [V4 PATCH 0/8] vlan extension - add readonly library code Message-ID: <1326879652-12092-1-git-send-email-xiawenc@linux.vnet.ibm.com> These patches just add new library in libvirt-cim and do not touch existing providers. It have a testing program added to see the functionalities. V2: fix some problem in filter out NICs. V3: using libnl3 and libbridge instead of string parsing, applys to libvirt-cim 0.5.5. V4: switched to libnl1, using custom codes for bridge. Small fix about date declaration. libnl1 provides less functions such as single root NICs, but it is workable for vlan 8021q. Patch applys to latest libvirt-cim from git. repository: git://gitorious.org/libvirt-cim_develop/libvirt-cim_develop.git page: https://gitorious.org/libvirt-cim_develop/libvirt-cim_develop Wenchao Xia (8): vlan library - Makefile system change vlan library - add missing header files in libnl-devel 1.1 vlan library - add a simple implemention for bridge vlan library - add host network implemention vlan library - add basic structure and related functions vlan library - add help functions and error defines vlan library - add interface for CIM model code vlan library - testing program for libnetwork Makefile.am | 2 +- acinclude.m4 | 9 + configure.ac | 8 + libnetwork/Makefile.am | 37 ++ libnetwork/dll_magic.h | 13 + libnetwork/host_network_API.c | 30 + libnetwork/host_network_API.h | 25 + libnetwork/host_network_basic.c | 656 ++++++++++++++++++++++ libnetwork/host_network_basic.h | 158 ++++++ libnetwork/host_network_error.h | 23 + libnetwork/host_network_helper.c | 266 +++++++++ libnetwork/host_network_helper.h | 177 ++++++ libnetwork/host_network_implement_OSAPI.c | 366 ++++++++++++ libnetwork/host_network_implement_OSAPI.h | 21 + libnetwork/host_network_implement_bridge.c | 224 ++++++++ libnetwork/host_network_implement_bridge.h | 8 + libnetwork/include/netlink/route/link/info-api.h | 71 +++ libnetwork/include/netlink/route/link/vlan.h | 55 ++ libnetwork/libnetwork_test.c | 91 +++ libvirt-cim.spec.in | 2 + 20 files changed, 2241 insertions(+), 1 deletions(-) create mode 100644 libnetwork/Makefile.am create mode 100644 libnetwork/dll_magic.h create mode 100644 libnetwork/host_network_API.c create mode 100644 libnetwork/host_network_API.h create mode 100644 libnetwork/host_network_basic.c create mode 100644 libnetwork/host_network_basic.h create mode 100644 libnetwork/host_network_error.h create mode 100644 libnetwork/host_network_helper.c create mode 100644 libnetwork/host_network_helper.h create mode 100644 libnetwork/host_network_implement_OSAPI.c create mode 100644 libnetwork/host_network_implement_OSAPI.h create mode 100644 libnetwork/host_network_implement_bridge.c create mode 100644 libnetwork/host_network_implement_bridge.h create mode 100644 libnetwork/include/netlink/route/link/info-api.h create mode 100644 libnetwork/include/netlink/route/link/vlan.h create mode 100644 libnetwork/libnetwork_test.c From xiawenc at linux.vnet.ibm.com Wed Jan 18 09:41:16 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Wed, 18 Jan 2012 17:41:16 +0800 Subject: [Libvirt-cim] [V4 PATCH 1/8] vlan library - Makefile system change Message-ID: <1326879676-12143-1-git-send-email-xiawenc@linux.vnet.ibm.com> building system is changed to check libnl-devel-1.1. Also added Makefile in sub dir. In sub dir CFLAGS and LDFLAGS were overwritten, because they have other values set when configure was excuted. Libnetwork have -fPIC and -fvisibility=hidden -D DLL_BUILD flags set. Signed-off-by: Wenchao Xia --- Makefile.am | 2 +- acinclude.m4 | 9 +++++++++ configure.ac | 8 ++++++++ libnetwork/Makefile.am | 37 +++++++++++++++++++++++++++++++++++++ libvirt-cim.spec.in | 2 ++ 5 files changed, 57 insertions(+), 1 deletions(-) create mode 100644 libnetwork/Makefile.am diff --git a/Makefile.am b/Makefile.am index 94dc5f3..6689550 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ # Copyright IBM Corp. 2007 AUTOMAKE_OPTIONS=dist-bzip2 -SUBDIRS = libxkutil src doc base_schema +SUBDIRS = libnetwork libxkutil src doc base_schema MOFS = \ $(top_srcdir)/schema/ComputerSystem.mof \ diff --git a/acinclude.m4 b/acinclude.m4 index e0f76b6..3a2f76f 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -387,3 +387,12 @@ AC_DEFUN([SET_CSET], CFLAGS="$CFLAGS $cs $rv" ] ) + +AC_DEFUN([CHECK_LIBNL], + [ + PKG_CHECK_MODULES([LIBNL], [libnl-1 >= 1.1]) + AC_SUBST([LIBNL_CFLAGS]) + AC_SUBST([LIBNL_LIBS]) +# CPPFLAGS="$CPPFLAGS $LIBNL_CFLAGS" +# LDFLAGS="$LDFLAGS $LIBNL_LIBS" + ]) diff --git a/configure.ac b/configure.ac index 0f85baa..78a7438 100644 --- a/configure.ac +++ b/configure.ac @@ -50,6 +50,12 @@ CC_WARNINGS="\ CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE -D_LARGEFILE64_SOURCE" +# following are for libnetwork +LIBNETWORK_CFLAGS="-fvisibility=hidden" +LIBNETWORK_DEFINES="-D DLL_BUILD" +AC_SUBST(LIBNETWORK_CFLAGS) +AC_SUBST(LIBNETWORK_DEFINES) + # Configure command line options AC_ARG_VAR([CIMSERVER],[the target CIM server (pegasus|sfcb|openwbem|sniacimom). ]) @@ -141,6 +147,7 @@ AC_CONFIG_FILES([ base_schema/install_base_schema.sh base_schema/Makefile libxkutil/Makefile + libnetwork/Makefile src/Makefile doc/Makefile Makefile @@ -165,6 +172,7 @@ CHECK_LIBXML2 CHECK_LIBCU CHECK_LIBUUID CHECK_LIBCONFIG +CHECK_LIBNL CFLAGS_STRICT="-Werror" diff --git a/libnetwork/Makefile.am b/libnetwork/Makefile.am new file mode 100644 index 0000000..aaa33c0 --- /dev/null +++ b/libnetwork/Makefile.am @@ -0,0 +1,37 @@ +# Copyright IBM Corp. 2012 +# Auther: +# Wenchao Xia, +# +# Try build a dynamic library libnetwork.so, which +# include libnl-3 and libbridge binaries. Doing this is +# because there is no devel-libbridge.rpm, and there are +# many program still using libnl1.so, which conflicts with +# libnl-3. +# Exported symbols are strictly limited by Macro DLL_PUBLIC +# to reduce name space polution. +# It need libcmpiutil to use CU_DEBUG facility. +# A test program is generated named as libnetwork_test. + +LDFLAGS = $(LIBNETWORK_DEFINES) + +CFLAGS = $(CFLAGS_STRICT) \ + -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" \ + $(LIBNETWORK_CFLAGS) $(LIBNETWORK_DEFINES) \ + -I $(top_srcdir)/libnetwork/include + + +noinst_HEADERS = host_network_API.h host_network_basic.h host_network_helper.h host_network_error.h \ + host_network_implement_OSAPI.h host_network_implement_bridge.h dll_magic.h +noinst_HEADERS += include/netlink/route/link/vlan.h include/netlink/route/link/info-api.h + +lib_LTLIBRARIES = libnetwork.la + +libnetwork_la_SOURCES = host_network_API.c host_network_basic.c host_network_helper.c \ + host_network_implement_OSAPI.c host_network_implement_bridge.c +libnetwork_la_LDFLAGS = -version-info @VERSION_INFO@ -lcmpiutil $(LIBNL_LIBS) + +noinst_PROGRAMS = libnetwork_test + +libnetwork_test_SOURCES = libnetwork_test.c +libnetwork_test_LDFLAGS = -lcmpiutil +libnetwork_test_LDADD = libnetwork.la diff --git a/libvirt-cim.spec.in b/libvirt-cim.spec.in index d78eee7..5fac166 100644 --- a/libvirt-cim.spec.in +++ b/libvirt-cim.spec.in @@ -13,9 +13,11 @@ Requires: libxml2 >= 2.6.0 Requires: libvirt >= 0.9.0 Requires: unzip Requires: tog-pegasus +Requires: libnl >= 1.1 BuildRequires: libcmpiutil >= 0.5.4 BuildRequires: tog-pegasus-devel BuildRequires: libvirt-devel >= 0.9.0 +BuildRequires: libnl-devel >= 1.1 # In RHEL5 uuid-devel is provided by e2fsprogs %if 0%{?el5} -- 1.7.1 From xiawenc at linux.vnet.ibm.com Wed Jan 18 09:41:44 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Wed, 18 Jan 2012 17:41:44 +0800 Subject: [Libvirt-cim] [V4 PATCH 2/8] vlan library - add missing header files in libnl-devel 1.1 Message-ID: <1326879704-12189-1-git-send-email-xiawenc@linux.vnet.ibm.com> Because libnl-devel-1.1 package missed some header files even if functions are included in its .so file, they are directly be put here. Codes are from the help documents that libnl-devel-1.1 provides. Signed-off-by: Wenchao Xia --- libnetwork/include/netlink/route/link/info-api.h | 71 ++++++++++++++++++++++ libnetwork/include/netlink/route/link/vlan.h | 55 +++++++++++++++++ 2 files changed, 126 insertions(+), 0 deletions(-) create mode 100644 libnetwork/include/netlink/route/link/info-api.h create mode 100644 libnetwork/include/netlink/route/link/vlan.h diff --git a/libnetwork/include/netlink/route/link/info-api.h b/libnetwork/include/netlink/route/link/info-api.h new file mode 100644 index 0000000..7a2e498 --- /dev/null +++ b/libnetwork/include/netlink/route/link/info-api.h @@ -0,0 +1,71 @@ +/* + * netlink/route/link/info-api.h Link Info API + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_LINK_INFO_API_H_ +#define NETLINK_LINK_INFO_API_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @ingroup link_info + * + * Link info operations + */ +struct rtnl_link_info_ops +{ + /** Name of operations, must match name on kernel side */ + char * io_name; + + /** Reference count (internal, do not use) */ + int io_refcnt; + + /** Called to assign an info type to a link. + * Has to allocate enough resources to hold attributes. Can + * use link->l_info to store a pointer. */ + int (*io_alloc)(struct rtnl_link *); + + /** Called to parse the link info attribute. + * Must parse the attribute and assign all values to the link. + */ + int (*io_parse)(struct rtnl_link *, + struct nlattr *, + struct nlattr *); + + /** Called when the link object is dumped. + * Must dump the info type specific attributes. */ + int (*io_dump[NL_DUMP_MAX+1])(struct rtnl_link *, + struct nl_dump_params *, int); + + /** Called when a link object is cloned. + * Must clone all info type specific attributes. */ + int (*io_clone)(struct rtnl_link *, struct rtnl_link *); + + /** Called when construction a link netlink message. + * Must append all info type specific attributes to the message. */ + int (*io_put_attrs)(struct nl_msg *, struct rtnl_link *); + + /** Called to release all resources previously allocated + * in either io_alloc() or io_parse(). */ + void (*io_free)(struct rtnl_link *); + + struct rtnl_link_info_ops * io_next; +}; + +extern struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *); + +extern int rtnl_link_register_info(struct rtnl_link_info_ops *); +extern int rtnl_link_unregister_info(struct rtnl_link_info_ops *); + +#endif diff --git a/libnetwork/include/netlink/route/link/vlan.h b/libnetwork/include/netlink/route/link/vlan.h new file mode 100644 index 0000000..80aa921 --- /dev/null +++ b/libnetwork/include/netlink/route/link/vlan.h @@ -0,0 +1,55 @@ +/* + * netlink/route/link/vlan.h VLAN interface + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#ifndef NETLINK_LINK_VLAN_H_ +#define NETLINK_LINK_VLAN_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct vlan_map +{ + uint32_t vm_from; + uint32_t vm_to; +}; + +#define VLAN_PRIO_MAX 7 + +extern char * rtnl_link_vlan_flags2str(int, char *, size_t); +extern int rtnl_link_vlan_str2flags(const char *); + +extern int rtnl_link_vlan_set_id(struct rtnl_link *, int); +extern int rtnl_link_vlan_get_id(struct rtnl_link *); + +extern int rtnl_link_vlan_set_flags(struct rtnl_link *, + unsigned int); +extern int rtnl_link_vlan_unset_flags(struct rtnl_link *, + unsigned int); +extern unsigned int rtnl_link_vlan_get_flags(struct rtnl_link *); + +extern int rtnl_link_vlan_set_ingress_map(struct rtnl_link *, + int, uint32_t); +extern uint32_t * rtnl_link_vlan_get_ingress_map(struct rtnl_link *); + +extern int rtnl_link_vlan_set_egress_map(struct rtnl_link *, + uint32_t, int); +extern struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *, + int *); + +#ifdef __cplusplus +} +#endif + +#endif -- 1.7.1 From xiawenc at linux.vnet.ibm.com Wed Jan 18 09:42:00 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Wed, 18 Jan 2012 17:42:00 +0800 Subject: [Libvirt-cim] [V4 PATCH 3/8] vlan library - add a simple implemention for bridge Message-ID: <1326879720-12235-1-git-send-email-xiawenc@linux.vnet.ibm.com> This patch use ioctl to get bridge settings from kernel. Netlink protocol can't be used for bridge in linux2.6 kernel. ioctl is the oldest way to talk to kernel about bridge, so it have some limit in the ports number and bridge number. Currently they are set to 1024. Signed-off-by: Wenchao Xia --- libnetwork/host_network_implement_bridge.c | 224 ++++++++++++++++++++++++++++ libnetwork/host_network_implement_bridge.h | 8 + 2 files changed, 232 insertions(+), 0 deletions(-) create mode 100644 libnetwork/host_network_implement_bridge.c create mode 100644 libnetwork/host_network_implement_bridge.h diff --git a/libnetwork/host_network_implement_bridge.c b/libnetwork/host_network_implement_bridge.c new file mode 100644 index 0000000..39c6b13 --- /dev/null +++ b/libnetwork/host_network_implement_bridge.c @@ -0,0 +1,224 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "host_network_implement_bridge.h" +#include "host_network_helper.h" +#include "host_network_error.h" + +/* following number can't be changed otherwise ioctl get errors */ +#define BR_NUM_MAX 1024 +#define PORT_NUM_MAX 1024 +#define NAME_BUFF_SIZE 16 + +static int socket_br = -1; + +static int try_socket_init(void) +{ + if (socket_br < 0) { + if ((socket_br = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) + return -errno; + } + return 1; +} + +void try_socket_close(void) +{ + if (socket_br > 0) { + close(socket_br); + socket_br = -1; + } +} + +static int get_bridge_ports(EthIface *piface) +{ + struct ifreq req; + char ifname[NAME_BUFF_SIZE]; + int if_indexes[PORT_NUM_MAX]; + unsigned long args[4]; + int i, ret = ERR_LIBBR; + BR_Prop *pbr; + + memset(ifname, 0, sizeof(ifname)); + memset(&req, 0 ,sizeof(req)); + memset(if_indexes, 0 ,sizeof(if_indexes)); + args[0] = BRCTL_GET_PORT_LIST; + args[1] = (unsigned long)if_indexes; + args[2] = PORT_NUM_MAX; + args[3] = 0; + + strncpy(req.ifr_name, piface->name, NAME_BUFF_SIZE); + req.ifr_data = (char *) &args; + + if (0 > ioctl(socket_br, SIOCDEVPRIVATE, &req)) { + CU_DEBUG("failed in ioctl listing ports of bridge %s," + " errno %d, reason %s.", + piface->name, errno, strerror(errno)); + goto out; + } + + if (piface->pbr_prop == NULL) { + eth_iface_add_br_prop(piface); + } + pbr = piface->pbr_prop; + + i = -1; + while (i < PORT_NUM_MAX) { + i++; + if (if_indexes[i] <= 0) { + continue; + } + if (0 == if_indextoname(if_indexes[i], ifname)) { + CU_DEBUG("failed to translate if_index %d, skip it.", if_indexes); + continue; + } + /* add the ports to the list */ + if (pbr->port_names == NULL) { + SAFE_CALLOC(pbr->port_names, + MAX_IFACE_NUM, sizeof(char *)); + pbr->port_num = 0; + } + if (pbr->port_num >= MAX_IFACE_NUM) { + CU_DEBUG("bridge [%s] have too much eth attached!", piface->name); + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + pbr->port_names[pbr->port_num] = SAFE_STRDUP(ifname); + pbr->port_num++; + } + + ret = 1; + + out: + return ret; +} + +static int get_bridge_info(EthIface *piface) +{ + struct ifreq req; + struct __bridge_info binfo; + unsigned long args[4]; + int ret = ERR_LIBBR; + + memset(&req, 0, sizeof(req)); + memset(&binfo, 0, sizeof(binfo)); + args[0] = BRCTL_GET_BRIDGE_INFO; + args[1] = (unsigned long) &binfo; + args[2] = 0; + args[3] = 0; + req.ifr_data = (char *) &args; + + if (piface->name == NULL) { + CU_DEBUG("bridge name not set for ioctl."); + goto out; + } + strncpy(req.ifr_name, piface->name, NAME_BUFF_SIZE); + if (ioctl(socket_br, SIOCDEVPRIVATE, &req) < 0) { + CU_DEBUG("failed to get info for %s, errno %d, reason %s.", + piface->name, errno, strerror(errno)); + goto out; + } + + if (piface->pbr_prop == NULL) { + eth_iface_add_br_prop(piface); + } + piface->pbr_prop->STP = binfo.stp_enabled; + + ret = 1; + + out: + return ret; +} + +static int list_bridges(EthIfacesList *plist) +{ + int if_indexes[BR_NUM_MAX]; + unsigned long args[3]; + int brnum; + int i, ret = ERR_LIBBR; + EthIface tface; + + eth_iface_init(&tface); + SAFE_CALLOC(tface.name, NAME_BUFF_SIZE, 1); + + args[0] = BRCTL_GET_BRIDGES; + args[1] = (unsigned long)if_indexes; + args[2] = BR_NUM_MAX; + memset(if_indexes, 0, sizeof(if_indexes)); + + if (0 > try_socket_init()) { + CU_DEBUG("failed to init socket for bridge ioctl," + " errno is %d, reason: %s.", + errno, strerror(errno)); + goto out; + } + + brnum = ioctl(socket_br, SIOCGIFBR, args); + if (brnum < 0) { + CU_DEBUG("failed tp get bridge, errno is %d, reason: %s.", + errno, strerror(errno)); + goto out; + } + + i = 0; + while (i < brnum) { + if (!if_indextoname(if_indexes[i], tface.name)) { + CU_DEBUG("failed to translate index %d, errno is %d, reason: %s.", + if_indexes[i], errno, strerror(errno)); + goto out; + } + + ret = get_bridge_info(&tface); + if (ret != 1) { + CU_DEBUG("failed to get info for %s.", tface.name); + continue; + } + + ret = get_bridge_ports(&tface); + if (ret != 1) { + CU_DEBUG("failed to get info for %s.", tface.name); + continue; + } + + if (1 != eth_ifaceslist_add(plist, &tface)) { + CU_DEBUG("failed to add device to list."); + goto out; + } + eth_iface_uninit(&tface); + eth_iface_init(&tface); + SAFE_CALLOC(tface.name, NAME_BUFF_SIZE, 1); + i++; + } + ret = 1; + + out: + eth_iface_uninit(&tface); + try_socket_close(); + return ret; + +} + +int get_host_eth_ifaces_osapi_bridge(EthIfacesList *plist) +{ + return list_bridges(plist); +} diff --git a/libnetwork/host_network_implement_bridge.h b/libnetwork/host_network_implement_bridge.h new file mode 100644 index 0000000..ed77195 --- /dev/null +++ b/libnetwork/host_network_implement_bridge.h @@ -0,0 +1,8 @@ +#ifndef HOST_NETWORK_IMPLE_BRIDGE_H +#define HOST_NETWORK_IMPLE_BRIDGE_H + +#include "host_network_basic.h" + +int get_host_eth_ifaces_osapi_bridge(EthIfacesList *plist); + +#endif -- 1.7.1 From xiawenc at linux.vnet.ibm.com Wed Jan 18 09:42:12 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Wed, 18 Jan 2012 17:42:12 +0800 Subject: [Libvirt-cim] [V4 PATCH 4/8] vlan library - add host network implemention Message-ID: <1326879732-12265-1-git-send-email-xiawenc@linux.vnet.ibm.com> This patch use libnl-1.1 and ioctl bridge functions in patch 3. Signed-off-by: Wenchao Xia --- libnetwork/host_network_implement_OSAPI.c | 366 +++++++++++++++++++++++++++++ libnetwork/host_network_implement_OSAPI.h | 21 ++ 2 files changed, 387 insertions(+), 0 deletions(-) create mode 100644 libnetwork/host_network_implement_OSAPI.c create mode 100644 libnetwork/host_network_implement_OSAPI.h diff --git a/libnetwork/host_network_implement_OSAPI.c b/libnetwork/host_network_implement_OSAPI.c new file mode 100644 index 0000000..2efcf37 --- /dev/null +++ b/libnetwork/host_network_implement_OSAPI.c @@ -0,0 +1,366 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "host_network_implement_bridge.h" +#include "host_network_implement_OSAPI.h" +#include "host_network_helper.h" +#include "host_network_error.h" + +/* macro defines */ +#define LN_PRINT_LEVEL 4 + +struct nl_add2list_param { + EthIfacesList *plist; + struct nl_cache *cache; +} ; + +/* libnl1 lackes a way to see if it is vlan8021q, added an implemention here*/ +static int rtnl_link_is_vlan(struct rtnl_link *link) +{ + char* type = rtnl_link_get_info_type(link); + if (type == NULL) { + return 0; + } + return !strcmp(type, "vlan"); +} + +/* the bridge seems have 0 value when it is up , so adjust the value, + and found out which are physical cards */ +static int host_iface_adjust(EthIface *piface) +{ + if (1 == eth_iface_filter_peths(piface, NULL)) { + piface->eth_type |= (ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_PHYSICAL); + } + return 1; +} + +static void find_iface_attached_bridge(EthIfacesList *peth_list, EthIface *pbr) +{ + int i, j; + char *name_on_br, *name_iface; + if (pbr->pbr_prop == NULL) { + return; + } + i = 0; + while (i < pbr->pbr_prop->port_num) { + name_on_br = pbr->pbr_prop->port_names[i]; + j = 0; + while (j < peth_list->count) { + name_iface = peth_list->pifaces[j]->name; + if (0 == strcmp(name_on_br, name_iface)) { + if (peth_list->pifaces[j]->attach_bridge == NULL) { + peth_list->pifaces[j]->attach_bridge = + SAFE_STRDUP(pbr->name); + } + break; + } + j++; + } + i++; + } +} + +/* assuming that one peth would be attached to at most 1 bridge */ +static void merge_eth_list_for_bridge(EthIfacesList *peth_list, + EthIfacesList *pbr_list, + int flag) +{ + int i, j; + i = 0; + while (i < pbr_list->count) { + find_iface_attached_bridge(peth_list, pbr_list->pifaces[i]); + j = 0; + while (j < peth_list->count) { + if (1 == eth_iface_compare(peth_list->pifaces[j], + pbr_list->pifaces[i])) { + /* found the matched device, merge them */ + eth_iface_merge(peth_list->pifaces[j], + pbr_list->pifaces[i], flag); + break; + } + j++; + } + i++; + } + return; +} + +static void ln_link_print(struct rtnl_link *link) +{ + char *name, *qdisk, *type = NULL; + const char *ifalias = NULL; + int ifindex, flags, mtu, txqlen, family, arptype, getlink, master, operstate, linkmode; + uint32_t num_vf = 0; + int ret, i; + int vlanid, vlanflag, egress_num = 0; + uint32_t *ingress_map; + struct vlan_map *egress_map; + + qdisk = rtnl_link_get_qdisc(link); + name = rtnl_link_get_name(link); + flags = rtnl_link_get_flags(link); + mtu = rtnl_link_get_mtu(link); + txqlen = rtnl_link_get_txqlen(link); + ifindex = rtnl_link_get_ifindex(link); + family = rtnl_link_get_family(link); + arptype = rtnl_link_get_arptype(link); + getlink = rtnl_link_get_link(link); + master = rtnl_link_get_master(link); + operstate = rtnl_link_get_operstate(link); + linkmode = rtnl_link_get_linkmode(link); + + CMD_DEBUG(1, "link name %s, alias %s, qdisk %s, type %s,\n" + "--ifindex 0x%x, flags 0x%x, mtu 0x%x, txqlen 0x%x, family 0x%x, arptype 0x%x,\n" + "--getlink 0x%x, master 0x%x, operstate 0x%x, linkmode 0x%x, vf_ret %d with num_vf 0x%x.\n", + name, ifalias, qdisk, type, + ifindex, flags, mtu, txqlen, family, arptype, + getlink, master, operstate, linkmode, ret, num_vf); + + if (rtnl_link_is_vlan(link)) { + vlanid = rtnl_link_vlan_get_id(link); + vlanflag = rtnl_link_vlan_get_flags(link); + ingress_map = rtnl_link_vlan_get_ingress_map(link); + egress_map = rtnl_link_vlan_get_egress_map(link, &egress_num); + CMD_DEBUG(1, "--vlan properties:\n" + "----id %d, vlanflag 0x%x.", + vlanid, vlanflag); + CMD_DEBUG(1, "\n----ingress: "); + if (ingress_map != NULL) { + for (i = 0; i <= VLAN_PRIO_MAX; i++) { + CMD_DEBUG(1, "0x%x, ", ingress_map[i]); + } + } + CMD_DEBUG(1, "\n----egress: "); + if (egress_map != NULL) { + i = 0; + while (i < egress_num) { + CMD_DEBUG(1, "[%d %d], ", egress_map[i].vm_from, egress_map[i].vm_to); + i++; + } + } + CMD_DEBUG(1, "\n"); + } +} + +static void nl_add2list_func(struct nl_object *obj, void *opaque) +{ + struct rtnl_link *link; + struct nl_cache *cache; + struct rtnl_link *ll; + struct nl_addr *addr; + uint32_t *ingress_map; + int egress_num = 0, opstate; + struct vlan_map *egress_map; + EthIfacesList *plist; + EthIface tface; + VLAN_Prop_8021q *pprop_8021q; + char buf[128]; + int t, i; + + struct nl_add2list_param *pparam = (struct nl_add2list_param *)opaque; + plist = pparam->plist; + cache = pparam->cache; + link = (struct rtnl_link *)obj; + + if (CMD_DEBUG_LEVEL && (LN_PRINT_LEVEL) <= CMD_DEBUG_LEVEL) { + ln_link_print(link); + } + + /* get properties */ + eth_iface_init(&tface); + + /* get name */ + tface.name = SAFE_STRDUP(rtnl_link_get_name(link)); + + /* get parent */ + t = rtnl_link_get_link(link); + if (t > 0) { + ll = rtnl_link_get(cache, t); + if (ll == NULL) { + CU_DEBUG("failed to find interface with index %d.", t); + goto out; + } + tface.dep_ifname = SAFE_STRDUP(rtnl_link_get_name(ll)); + rtnl_link_put(ll); + } + + /* get mac */ + addr =rtnl_link_get_addr(link); + if (addr && !nl_addr_iszero(addr)) { + nl_addr2str(addr, buf, sizeof(buf)); + tface.mac = SAFE_STRDUP(buf); + } + + /* get main type */ + t = rtnl_link_get_arptype(link); + if (t == ARPHRD_ETHER) { + tface.eth_type = ETH_TYPE_ETHER_ANY; + } else { + tface.eth_type = ETH_TYPE_OTHER; + } + + tface.run_prop.status = rtnl_link_get_operstate(link); + + /* get vlan */ + if (rtnl_link_is_vlan(link)) { + SAFE_MALLOC(tface.pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(tface.pvlan_prop, VLAN_TYPE_802_1_Q); + pprop_8021q = &(tface.pvlan_prop->props.prop_8021q); + tface.eth_type |= ETH_TYPE_ETHER_SUB_VLAN; + pprop_8021q->vlan_id = rtnl_link_vlan_get_id(link); + pprop_8021q->reorder_hdr = (rtnl_link_vlan_get_flags(link) & + VLAN_FLAG_REORDER_HDR); + /* at any time parent of vlan8021.q is just what it depends on */ + pprop_8021q->parent = SAFE_STRDUP(tface.dep_ifname); + ingress_map = rtnl_link_vlan_get_ingress_map(link); + egress_map = rtnl_link_vlan_get_egress_map(link, &egress_num); + if (ingress_map != NULL) { + for (i = 0; i <= VLAN_PRIO_MAX; i++) { + pprop_8021q->ingress.values[i].from = i; + pprop_8021q->ingress.values[i].to = ingress_map[i]; + } + pprop_8021q->ingress.count = VLAN_PRIO_MAX; + i = 0; + while (i < egress_num) { + pprop_8021q->egress.values[i].from = egress_map[i].vm_from; + pprop_8021q->egress.values[i].to = egress_map[i].vm_to; + i++; + } + pprop_8021q->egress.count = egress_num; + } + } + + /* put result to list */ + if (1 != eth_ifaceslist_add(plist, &tface)) { + CU_DEBUG("failed to add device to list."); + goto out; + } + + out: + eth_iface_uninit(&tface); +} + +static int get_host_eth_ifaces_osapi_netlink(EthIfacesList *plist) +{ + struct nl_handle *nlh = NULL; + struct nl_cache *cache = NULL; + int ret, rtnl_ret; + struct nl_add2list_param param; + + nlh = nl_handle_alloc(); + if (nlh == NULL) { + CU_DEBUG("unable to allocate nl handle."); + ret = ERR_LIBNETLINK; + } + rtnl_ret = nl_connect(nlh, NETLINK_ROUTE); + if (rtnl_ret < 0) { + CU_DEBUG("error in connect to kernel, return %d, err %s.\n", + rtnl_ret, nl_geterror()); + ret = ERR_LIBNETLINK; + } + + cache = rtnl_link_alloc_cache(nlh); + if (cache == NULL) { + CU_DEBUG("error in talking to kernel.\n"); + ret = ERR_LIBNETLINK; + } + + param.plist = plist; + param.cache = cache; + nl_cache_foreach(cache, nl_add2list_func, ¶m); + if (plist->count >= MAX_IFACE_NUM) { + CU_DEBUG("too much device found."); + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + + ret = 1; + + out: + nl_cache_free(cache); + nl_close(nlh); + nl_handle_destroy(nlh); + + return ret; +} + +int get_host_eth_ifaces_osapi(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque) +{ + int retvalue; + EthIfacesList *ifaces1, *ifaces2; + int i; + int filter_ret; + int count = 0; + SAFE_MALLOC(ifaces1, sizeof(EthIfacesList)); + SAFE_MALLOC(ifaces2, sizeof(EthIfacesList)); + eth_ifaceslist_init(ifaces1); + eth_ifaceslist_init(ifaces2); + + retvalue = get_host_eth_ifaces_osapi_netlink(ifaces1); + if (retvalue != 1) { + goto out; + } + + retvalue = get_host_eth_ifaces_osapi_bridge(ifaces2); + if (retvalue != 1) { + goto out; + } + /* merge the information */ + merge_eth_list_for_bridge(ifaces1, ifaces2, 1); + eth_ifaceslist_uninit(ifaces2); + + /* filter the result */ + i = 0; + while (i < ifaces1->count) { + /* see if the result need to be put to the list */ + filter_ret = 1; + if (filter_func != NULL) { + filter_ret = filter_func(ifaces1->pifaces[i], filter_opaque); + } + if (filter_ret == 1) { + if (count >= MAX_IFACE_NUM) { + retvalue = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + host_iface_adjust(ifaces1->pifaces[i]); + plist->pifaces[count] = ifaces1->pifaces[i]; + ifaces1->pifaces[i] = NULL; + count++; + } + i++; + } + + out: + eth_ifaceslist_uninit(ifaces1); + SAFE_FREE(ifaces1); + eth_ifaceslist_uninit(ifaces2); + SAFE_FREE(ifaces2); + plist->count = count; + return retvalue; +} diff --git a/libnetwork/host_network_implement_OSAPI.h b/libnetwork/host_network_implement_OSAPI.h new file mode 100644 index 0000000..34a261b --- /dev/null +++ b/libnetwork/host_network_implement_OSAPI.h @@ -0,0 +1,21 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#ifndef HOST_NETWORK_IMPLEMENT_OSAPI_H +#define HOST_NETWORK_IMPLEMENT_OSAPI_H + +#include "host_network_basic.h" + +int get_host_eth_ifaces_osapi(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque); + +#endif -- 1.7.1 From xiawenc at linux.vnet.ibm.com Wed Jan 18 09:42:26 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Wed, 18 Jan 2012 17:42:26 +0800 Subject: [Libvirt-cim] [V4 PATCH 5/8] vlan library - add basic structure and related functions Message-ID: <1326879746-12316-1-git-send-email-xiawenc@linux.vnet.ibm.com> this patch have the structure defines and related functions, make program in upper level easy to use. Signed-off-by: Wenchao Xia --- libnetwork/host_network_basic.c | 656 +++++++++++++++++++++++++++++++++++++++ libnetwork/host_network_basic.h | 158 ++++++++++ 2 files changed, 814 insertions(+), 0 deletions(-) create mode 100644 libnetwork/host_network_basic.c create mode 100644 libnetwork/host_network_basic.h diff --git a/libnetwork/host_network_basic.c b/libnetwork/host_network_basic.c new file mode 100644 index 0000000..9260b33 --- /dev/null +++ b/libnetwork/host_network_basic.c @@ -0,0 +1,656 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include "host_network_basic.h" +#include "host_network_helper.h" + +#include +#include +#include + +static void vlan_prop_print(VLAN_Prop *pvlan_prop) +{ + VLAN_Prop_8021q *p_8021q; + char *ingress = NULL, *egress = NULL; + CMD_DEBUG(1, "--VLAN props: type %d.\n", + pvlan_prop->vlan_type); + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + vlan_8021q_qos_num_to_str(&ingress, &(p_8021q->ingress)); + vlan_8021q_qos_num_to_str(&egress, &(p_8021q->egress)); + CMD_DEBUG(1, "----IEEE802.1.Q: id %d, reorder %d, priority %d, " + "ingress %s, egress %s, parent %s.\n", + p_8021q->vlan_id, p_8021q->reorder_hdr, p_8021q->priv_flag, + ingress, egress, p_8021q->parent); + } + SAFE_FREE(ingress); + SAFE_FREE(egress); +} + +static void br_prop_print(BR_Prop *pbr_prop) +{ + int i = 0; + CMD_DEBUG(1, "--Bridge props: id %s, stp %d, " + "bridge type %d, port_num %d.\n", + pbr_prop->bridge_id, pbr_prop->STP, + pbr_prop->type, pbr_prop->port_num); + if (pbr_prop->port_names != NULL) { + CMD_DEBUG(1, "----Ports attached: "); + while (i < pbr_prop->port_num) { + CMD_DEBUG(1, " %s,", *(pbr_prop->port_names+i)); + i++; + } + CMD_DEBUG(1, "\n"); + } +} + +void eth_iface_print(EthIface *piface) +{ + CMD_DEBUG(1, "Iface device: name %s.\n" + "--Main Props: parent %s, attach to %s, mac %s," + " RX %lld, TX %lld, status %d, iface type 0x%x.\n", + piface->name, piface->dep_ifname, piface->attach_bridge, + piface->mac, + piface->run_prop.rx_bytes, piface->run_prop.tx_bytes, + piface->run_prop.status, piface->eth_type); + if (piface->pbr_prop != NULL) { + br_prop_print(piface->pbr_prop); + } + if (piface->pvlan_prop != NULL) { + vlan_prop_print(piface->pvlan_prop); + } + return; +} + +void eth_ifaceslist_print(EthIfacesList *plist) +{ + int i = 0; + CMD_DEBUG(1, "Have %d ifaces in the list:\n", plist->count); + while (i < plist->count) { + CMD_DEBUG(1, "%04d ", i); + eth_iface_print(plist->pifaces[i]); + i++; + } +} + +void vlan_prop_init(VLAN_Prop *pvlan_prop, int vlan_type) +{ + VLAN_Prop_8021q *p_8021q; + memset(pvlan_prop, 0, sizeof(VLAN_Prop)); + pvlan_prop->vlan_type = vlan_type; + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + p_8021q->ingress.count = NUM_NOT_GOT; + p_8021q->egress.count = NUM_NOT_GOT; + p_8021q->vlan_id = NUM_NOT_GOT; + p_8021q->reorder_hdr = NUM_NOT_GOT; + p_8021q->priv_flag = NUM_NOT_GOT; + } +} + +void br_prop_init(BR_Prop *pbr_prop) +{ + memset(pbr_prop, 0, sizeof(BR_Prop)); + pbr_prop->STP = NUM_NOT_GOT; + pbr_prop->type = BR_TYPE_NOT_GOT; + pbr_prop->port_num = NUM_NOT_GOT; +} + +void eth_iface_init(EthIface *piface) +{ + memset(piface, 0, sizeof(EthIface)); + piface->eth_type = ETH_TYPE_NOT_GOT; + piface->run_prop.rx_bytes = NUM_NOT_GOT; + piface->run_prop.tx_bytes = NUM_NOT_GOT; + piface->run_prop.status = NUM_NOT_GOT; + return; +} + +void eth_iface_add_br_prop(EthIface *piface) +{ + SAFE_MALLOC(piface->pbr_prop, sizeof(BR_Prop)); + br_prop_init(piface->pbr_prop); +} + +void eth_iface_add_vlan_prop(EthIface *piface, int vlan_type) +{ + SAFE_MALLOC(piface->pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(piface->pvlan_prop, vlan_type); +} + +void vlan_prop_uninit(VLAN_Prop *pvlan_prop) +{ + VLAN_Prop_8021q *p_8021q; + if (pvlan_prop == NULL) { + return; + } + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + SAFE_FREE(p_8021q->parent); + } +} + +void br_prop_uninit(BR_Prop *pbr_prop) +{ + int i; + if (pbr_prop == NULL) { + return; + } + SAFE_FREE(pbr_prop->bridge_id); + i = 0; + if (pbr_prop->port_names != NULL) { + while (i < pbr_prop->port_num) { + SAFE_FREE(pbr_prop->port_names[i]); + i++; + } + SAFE_FREE(pbr_prop->port_names); + } +} + +void eth_iface_uninit(EthIface *piface) +{ + if (piface == NULL) { + return; + } + SAFE_FREE(piface->name); + SAFE_FREE(piface->dep_ifname); + SAFE_FREE(piface->attach_bridge); + SAFE_FREE(piface->mac); + br_prop_uninit(piface->pbr_prop); + SAFE_FREE(piface->pbr_prop); + vlan_prop_uninit(piface->pvlan_prop); + SAFE_FREE(piface->pvlan_prop); + return; +} + +void eth_ifaces_clear(EthIface **ppifaces, int num) +{ + EthIface **t; + int i; + if (num <= 0) { + return; + } + t = ppifaces; + i = 0; + while (i < num) { + if (*t != NULL) { + eth_iface_uninit(*t); + SAFE_FREE(*t); + } + t++; + i++; + } + return; +} + +void eth_ifaceslist_init(EthIfacesList *plist) +{ + plist->count = 0; +} + +void eth_ifaceslist_uninit(EthIfacesList *plist) +{ + eth_ifaces_clear(plist->pifaces, plist->count); +} + +int eth_ifaceslist_add(EthIfacesList *plist, EthIface *piface) +{ + if (plist->count >= MAX_IFACE_NUM) { + CU_DEBUG("too much device found."); + return 0; + } + SAFE_MALLOC(plist->pifaces[plist->count], sizeof(EthIface)); + eth_iface_dup(plist->pifaces[plist->count], piface); + plist->count++; + return 1; +} + +static void vlan_prop_dup(VLAN_Prop *dest, const VLAN_Prop *src) +{ + VLAN_Prop_8021q *pd_8021q; + const VLAN_Prop_8021q *ps_8021q; + dest->vlan_type = src->vlan_type; + if (dest->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q = &(dest->props.prop_8021q); + ps_8021q = &(src->props.prop_8021q); + pd_8021q->vlan_id = ps_8021q->vlan_id; + pd_8021q->reorder_hdr = ps_8021q->reorder_hdr; + pd_8021q->priv_flag = ps_8021q->priv_flag; + pd_8021q->ingress = ps_8021q->ingress; + pd_8021q->egress = ps_8021q->egress; + pd_8021q->parent = SAFE_STRDUP(ps_8021q->parent); + } +} + +static void br_prop_dup(BR_Prop *dest, const BR_Prop *src) +{ + int i; + dest->bridge_id = SAFE_STRDUP(src->bridge_id); + dest->STP = src->STP; + dest->type = src->type; + SAFE_PSTR_ARRAY_DUP(dest->port_names, dest->port_num, + src->port_names, src->port_num, i); +} + +void eth_iface_dup(EthIface *dest, const EthIface *src) +{ + dest->name = SAFE_STRDUP(src->name); + dest->dep_ifname = SAFE_STRDUP(src->dep_ifname); + dest->attach_bridge = SAFE_STRDUP(src->attach_bridge); + dest->mac = SAFE_STRDUP(src->mac); + dest->eth_type = src->eth_type; + dest->run_prop.rx_bytes = src->run_prop.rx_bytes; + dest->run_prop.tx_bytes = src->run_prop.tx_bytes; + dest->run_prop.status = src->run_prop.status; + + if (src->pbr_prop != NULL) { + SAFE_MALLOC(dest->pbr_prop, sizeof(BR_Prop)); + /* doesn't need init it for that it would be copied at once */ + br_prop_dup(dest->pbr_prop, src->pbr_prop); + } else { + dest->pbr_prop = NULL; + } + + if (src->pvlan_prop != NULL) { + SAFE_MALLOC(dest->pvlan_prop, sizeof(VLAN_Prop)); + /* doesn't need init it for that it would be copied at once */ + vlan_prop_dup(dest->pvlan_prop, src->pvlan_prop); + } else { + dest->pvlan_prop = NULL; + } + +} + +int eth_iface_compare(const EthIface *p1, const EthIface *p2) +{ + int ret = 0; + if ((p1->name != NULL) || (p2->name != NULL)) { + if (0 == strcmp(p1->name, p2->name)) { + ret = 1; + } + } + return ret; +} + +static void vlan_prop_merge(VLAN_Prop *pdest, VLAN_Prop *psrc, int style) +{ + VLAN_Prop_8021q *pd_8021q, *ps_8021q; + + NUM_MERGE(pdest->vlan_type, psrc->vlan_type, VLAN_TYPE_NOT_GOT); + + if (psrc->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q = &(pdest->props.prop_8021q); + ps_8021q = &(psrc->props.prop_8021q); + NUM_MERGE(pd_8021q->vlan_id, ps_8021q->vlan_id, NUM_NOT_GOT); + NUM_MERGE(pd_8021q->reorder_hdr, ps_8021q->reorder_hdr, NUM_NOT_GOT); + NUM_MERGE(pd_8021q->priv_flag, ps_8021q->priv_flag, NUM_NOT_GOT); + if (pd_8021q->ingress.count == NUM_NOT_GOT) { + pd_8021q->ingress = ps_8021q->ingress; + } + if (pd_8021q->egress.count == NUM_NOT_GOT) { + pd_8021q->egress = ps_8021q->egress; + } + if (style == 0) { + CHARS_MERGE_NORMAL(pd_8021q->parent, ps_8021q->parent); + } else { + CHARS_MERGE_MOVE(pd_8021q->parent, ps_8021q->parent); + } + } +} + +static void br_prop_merge(BR_Prop *pdest, BR_Prop *psrc, int style) +{ + int i; + + if (style == 0) { + CHARS_MERGE_NORMAL(pdest->bridge_id, psrc->bridge_id); + /*merge it when dest have not been set */ + if (pdest->port_names == NULL) { + SAFE_PSTR_ARRAY_DUP(pdest->port_names, pdest->port_num, + psrc->port_names, psrc->port_num, i); + } + } else { + CHARS_MERGE_MOVE(pdest->bridge_id, psrc->bridge_id); + /*merge it when dest have not been set */ + if (pdest->port_names == NULL) { + pdest->port_names = psrc->port_names; + pdest->port_num = psrc->port_num; + psrc->port_names = NULL; + psrc->port_num = NUM_NOT_GOT; + } + } + NUM_MERGE(pdest->STP, psrc->STP, NUM_NOT_GOT); + NUM_MERGE(pdest->type, psrc->type, BR_TYPE_NOT_GOT); +} + +void eth_iface_merge(EthIface *dest, EthIface *src, int style) +{ + if (style == 0) { + CHARS_MERGE_NORMAL(dest->name, src->name); + CHARS_MERGE_NORMAL(dest->dep_ifname, src->dep_ifname); + CHARS_MERGE_NORMAL(dest->attach_bridge, src->attach_bridge); + CHARS_MERGE_NORMAL(dest->mac, src->mac); + } else { + CHARS_MERGE_MOVE(dest->name, src->name); + CHARS_MERGE_MOVE(dest->dep_ifname, src->dep_ifname); + CHARS_MERGE_MOVE(dest->attach_bridge, src->attach_bridge); + CHARS_MERGE_MOVE(dest->mac, src->mac); + } + + /* special case for eth_type*/ + if (dest->eth_type == ETH_TYPE_NOT_GOT) { + dest->eth_type = src->eth_type; + } else { + if ((src->eth_type & ETH_TYPE_ETHER_ANY) && + (dest->eth_type & ETH_TYPE_ETHER_ANY)) { + dest->eth_type |= (src->eth_type & ETH_TYPE_SUB_MASK); + } + } + + NUM_MERGE(dest->run_prop.rx_bytes, src->run_prop.rx_bytes, + NUM_NOT_GOT); + NUM_MERGE(dest->run_prop.tx_bytes, src->run_prop.tx_bytes, + NUM_NOT_GOT); + NUM_MERGE(dest->run_prop.status, src->run_prop.status, NUM_NOT_GOT); + + if (src->pbr_prop != NULL) { + if (dest->pbr_prop == NULL) { + SAFE_MALLOC(dest->pbr_prop, sizeof(BR_Prop)); + br_prop_init(dest->pbr_prop); + } + br_prop_merge(dest->pbr_prop, src->pbr_prop, style); + } + + if (src->pvlan_prop != NULL) { + if (dest->pvlan_prop == NULL) { + SAFE_MALLOC(dest->pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(dest->pvlan_prop, src->pvlan_prop->vlan_type); + } + vlan_prop_merge(dest->pvlan_prop, src->pvlan_prop, style); + } + +} + +/* compare qos values */ +static int VLAN_Qos_8021q_compare_by_ref(const VLAN_Qos_8021q *pqos, + const VLAN_Qos_8021q *pref) +{ + int ret = 1; + int i, j; + if (pref->count == NUM_NOT_GOT) { + /* do not need to compare*/ + goto out; + } + if ((pref->count < 0) || (pref->count > 8)) { + ret = 0; + goto out; + } + if ((pqos->count < 0) || (pqos->count > 8)) { + ret = 0; + goto out; + } + + i = 0; + while (i < pref->count) { + j = 0; + while (j < pqos->count) { + if (pref->values[i].from == pqos->values[j].from) { + if (pref->values[i].to != pqos->values[j].to) { + ret = 0; + goto out; + } + break; + } + j++; + } + if (j == pqos->count) { + ret = 0; + goto out; + } + i++; + } + + out: + return ret; +} + +static int vlan_prop_filter_by_ref(const VLAN_Prop *pvlan_prop, void *pref) +{ + int compare_result = 1; + VLAN_Prop *ref = (VLAN_Prop *)pref; + char *p1, *p2; + const VLAN_Prop_8021q *pd_8021q; + VLAN_Prop_8021q *pref_8021q; + + NUM_COMPARE_BY_REF(pvlan_prop->vlan_type, ref->vlan_type, + compare_result, VLAN_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + if (ref->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q = &(pvlan_prop->props.prop_8021q); + pref_8021q = &(ref->props.prop_8021q); + + NUM_COMPARE_BY_REF(pd_8021q->vlan_id, pref_8021q->vlan_id, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pd_8021q->reorder_hdr, pref_8021q->reorder_hdr, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pd_8021q->priv_flag, pref_8021q->priv_flag, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + compare_result = VLAN_Qos_8021q_compare_by_ref(&(pd_8021q->ingress), + &(pref_8021q->ingress)); + if (compare_result == 0) { + goto out; + } + + compare_result = VLAN_Qos_8021q_compare_by_ref(&(pd_8021q->egress), + &(pref_8021q->egress)); + if (compare_result == 0) { + goto out; + } + + p1 = pd_8021q->parent; + p2 = pref_8021q->parent; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + } + + out: + return compare_result; + +} + +static int br_prop_filter_by_ref(const BR_Prop *pbr_prop, void *pref) +{ + int compare_result = 1; + BR_Prop *ref = (BR_Prop *)pref; + char *p1, *p2; + + p1 = pbr_prop->bridge_id; + p2 = ref->bridge_id; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->STP, ref->STP, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->type, ref->type, + compare_result, BR_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->port_num, ref->port_num, + compare_result, NUM_NOT_GOT); + /* skip the comparation of ports it attached, user can define + a special filter for that */ + out: + return compare_result; +} + +int eth_iface_filter_by_ref(const EthIface *piface, void *pref) +{ + int compare_result = 1; + EthIface *ref = (EthIface *)pref; + char *p1, *p2; + + p1 = piface->name; + p2 = ref->name; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->dep_ifname; + p2 = ref->dep_ifname; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->attach_bridge; + p2 = ref->attach_bridge; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->mac; + p2 = ref->mac; + CHARS_COMPARE_CASE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + /* special case for eth_type */ + NUM_COMPARE_BY_REF((piface->eth_type & ETH_TYPE_BASE_MASK), + (ref->eth_type & ETH_TYPE_BASE_MASK), + compare_result, ETH_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + NUM_COMPARE_BY_REF((piface->eth_type & ETH_TYPE_SUB_MASK), + (ref->eth_type & ETH_TYPE_SUB_MASK), + compare_result, ETH_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(piface->run_prop.status, ref->run_prop.status, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + if (ref->pbr_prop != NULL) { + if (piface->pbr_prop != NULL) { + compare_result = br_prop_filter_by_ref(piface->pbr_prop, + ref->pbr_prop); + } else { + compare_result = 0; + } + if (compare_result == 0) { + goto out; + } + } + + if (ref->pvlan_prop != NULL) { + if (piface->pvlan_prop != NULL) { + compare_result = vlan_prop_filter_by_ref(piface->pvlan_prop, + ref->pvlan_prop); + + } else { + compare_result = 0; + } + if (compare_result == 0) { + goto out; + } + } + + out: + return compare_result; +} + +int eth_iface_filter_by_refname(const EthIface *piface, void *pref) +{ + int compare_result = 1; + EthIface *ref = (EthIface *)pref; + char *p1, *p2; + + p1 = piface->name; + p2 = ref->name; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + out: + return compare_result; +} + +int eth_iface_filter_vlans(const EthIface *piface, void *nouse) +{ + if (piface->name == NULL) { + return 0; + } + if (NULL == strstr(piface->name, ".")) { + return 0; + } else { + return 1; + } +} + +/* the judgement condition is weak, but I can't find a better way */ +int eth_iface_filter_peths(const EthIface *piface, void *nouse) +{ + if (!(piface->eth_type & ETH_TYPE_ETHER_ANY)) { + return 0; + } + if (piface->eth_type & ETH_TYPE_ETHER_SUB_BRIDGE) { + return 0; + } + if (piface->eth_type & ETH_TYPE_ETHER_SUB_VLAN) { + return 0; + } + if (piface->dep_ifname != NULL) { + return 0; + } + if (NULL != strstr(piface->name, ".")) { + return 0; + } + /* this filter NetUSB etc */ + if (NULL == strstr(piface->name, "eth")) { + return 0; + } + + return 1; +} diff --git a/libnetwork/host_network_basic.h b/libnetwork/host_network_basic.h new file mode 100644 index 0000000..f782e51 --- /dev/null +++ b/libnetwork/host_network_basic.h @@ -0,0 +1,158 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#ifndef NETWORK_BASIC_HOST_H +#define NETWORK_BASIC_HOST_H + +#include "dll_magic.h" + +/* value defines */ +#define MAX_IFACE_NUM 4096 + +#define NUM_NOT_GOT -1 + +#define ETH_TYPE_BASE_MASK 0xff00 +#define ETH_TYPE_SUB_MASK 0x00ff +typedef enum { + ETH_TYPE_NOT_GOT = 0x0000, + ETH_TYPE_UNKNOWN = 0x0100, + ETH_TYPE_OTHER = 0x0200, + ETH_TYPE_ETHER_ANY = 0x0400, + ETH_TYPE_ETHER_SUB_PHYSICAL = 0x0001, + ETH_TYPE_ETHER_SUB_BRIDGE = 0x0002, + ETH_TYPE_ETHER_SUB_VLAN = 0x0004 +} EthType; + +typedef enum { + BR_TYPE_NOT_GOT = NUM_NOT_GOT, + BR_TYPE_UNKNOWN = 0, + BR_TYPE_SWITCH = 1, + BR_TYPE_NAT = 2 +} BrType; + +typedef enum { + VLAN_TYPE_NOT_GOT = NUM_NOT_GOT, + VLAN_TYPE_802_1_Q = 1, + VLAN_TYPE_802_1_QBG = 2, + VLAN_TYPE_802_1_QBH = 4 +} VLANType; + +typedef struct BR_Prop { + char *bridge_id; + int STP; + BrType type; + char **port_names; + int port_num; +} BR_Prop; + +/* status use RFC 2863 operational status */ +typedef struct Run_Prop { + long long rx_bytes; + long long tx_bytes; + int status; +} Run_Prop; + +typedef struct VLAN_Qos_8021q_elem { + int from; + int to; +} VLAN_Qos_8021q_elem; + +typedef struct VLAN_Qos_8021q { + VLAN_Qos_8021q_elem values[8]; + int count; +} VLAN_Qos_8021q; + +typedef struct VLAN_Prop_8021q { + int vlan_id; + int reorder_hdr; + int priv_flag; + VLAN_Qos_8021q ingress; + VLAN_Qos_8021q egress; + char *parent; +} VLAN_Prop_8021q; + +/* HP vlan standard, TBD */ +typedef struct VLAN_Prop_8021qbg { + int invalid; +} VLAN_Prop_8021qbg; + +/* Cisco and VMware vlan standard, TBD */ +typedef struct VLAN_Prop_8021qbh { + int invalid; +} VLAN_Prop_8021qbh; + +typedef struct VLAN_Prop { + int vlan_type; + union { + VLAN_Prop_8021q prop_8021q; + VLAN_Prop_8021qbg prop_8021qbg; + VLAN_Prop_8021qbh prop_8021qbh; + } props; +} VLAN_Prop; + +/* EthIface is logical devices include eth ports and bridges */ +typedef struct EthIface { + char *name; + char *dep_ifname; /* parent dev name */ + char *attach_bridge; /* bridge the iface is attached to */ + char *mac; + EthType eth_type; + Run_Prop run_prop; + /* optional properties */ + BR_Prop *pbr_prop; + VLAN_Prop *pvlan_prop; +} EthIface; + +typedef struct EthIfacesList { + EthIface *pifaces[MAX_IFACE_NUM]; + int count; +} EthIfacesList; + +typedef int (*eth_iface_filter_func)(const EthIface *piface, void *opaque); + +/* uninit functions are only called when there is resource malloc */ +DLL_PUBLIC void vlan_prop_init(VLAN_Prop *pvlan_prop, int vlan_type); +DLL_PUBLIC void vlan_prop_uninit(VLAN_Prop *pvlan_prop); + +DLL_PUBLIC void br_prop_init(BR_Prop *pbr_prop); +DLL_PUBLIC void br_prop_uninit(BR_Prop *pbr_prop); + +DLL_PUBLIC void eth_iface_print(EthIface *piface); +DLL_PUBLIC void eth_iface_init(EthIface *piface); +DLL_PUBLIC void eth_iface_add_br_prop(EthIface *piface); +DLL_PUBLIC void eth_iface_add_vlan_prop(EthIface *piface, int vlan_type); +DLL_PUBLIC void eth_iface_uninit(EthIface *piface); +DLL_PUBLIC void eth_ifaces_clear(EthIface **ppifaces, int num); + +DLL_PUBLIC void eth_ifaceslist_init(EthIfacesList *plist); +DLL_PUBLIC void eth_ifaceslist_uninit(EthIfacesList *plist); +DLL_PUBLIC void eth_ifaceslist_print(EthIfacesList *plist); +DLL_PUBLIC int eth_ifaceslist_add(EthIfacesList *plist, EthIface *piface); + +/* this function assume dest have been uninited if it was used before*/ +DLL_PUBLIC void eth_iface_dup(EthIface *dest, const EthIface *src); + +/* see if it is refered to the same device */ +DLL_PUBLIC int eth_iface_compare(const EthIface *p1, const EthIface *p2); + +/* merge the properties that dest do not have value set, if style is set to 1, + the char* properties was moved instead of copy, safely reduce the memory + fragments, but src is modified. */ +DLL_PUBLIC void eth_iface_merge(EthIface *dest, EthIface *src, int style); + +DLL_PUBLIC int eth_iface_filter_by_ref(const EthIface *piface, void *pref); +DLL_PUBLIC int eth_iface_filter_by_refname(const EthIface *piface, void *pref); +DLL_PUBLIC int eth_iface_filter_vlans(const EthIface *piface, void *nouse); +DLL_PUBLIC int eth_iface_filter_peths(const EthIface *piface, void *nouse); + + +#endif -- 1.7.1 From xiawenc at linux.vnet.ibm.com Wed Jan 18 09:42:44 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Wed, 18 Jan 2012 17:42:44 +0800 Subject: [Libvirt-cim] [V4 PATCH 6/8] vlan library - add help functions and error defines Message-ID: <1326879764-12347-1-git-send-email-xiawenc@linux.vnet.ibm.com> This patch have help functions for libnetwork. It contains macro defines and help functions for host network configuration. It also provide some basic function such as conditional merge char*, int and properties of structure EthIface. Signed-off-by: Wenchao Xia --- libnetwork/dll_magic.h | 13 ++ libnetwork/host_network_error.h | 23 ++++ libnetwork/host_network_helper.c | 266 ++++++++++++++++++++++++++++++++++++++ libnetwork/host_network_helper.h | 177 +++++++++++++++++++++++++ 4 files changed, 479 insertions(+), 0 deletions(-) create mode 100644 libnetwork/dll_magic.h create mode 100644 libnetwork/host_network_error.h create mode 100644 libnetwork/host_network_helper.c create mode 100644 libnetwork/host_network_helper.h diff --git a/libnetwork/dll_magic.h b/libnetwork/dll_magic.h new file mode 100644 index 0000000..36bca83 --- /dev/null +++ b/libnetwork/dll_magic.h @@ -0,0 +1,13 @@ +#ifndef DLL_MAGIC_H +#define DLL_MAGIC_H + + +#if __GNUC__ >= 4 + #ifdef DLL_BUILD + #define DLL_PUBLIC __attribute__ ((visibility ("default"))) + #else + #define DLL_PUBLIC + #endif +#endif + +#endif diff --git a/libnetwork/host_network_error.h b/libnetwork/host_network_error.h new file mode 100644 index 0000000..1882172 --- /dev/null +++ b/libnetwork/host_network_error.h @@ -0,0 +1,23 @@ +#ifndef HOST_NETWORK_ERROR_H +#define HOST_NETWORK_ERROR_H + +#define ERR_REQUEST_NOT_SUPPORT -1 + +#define ERR_LIBNETLINK -80 +#define ERR_LIBBR -90 + +#define ERR_DEVICE_EXCEED_MAXNUM -100 +#define ERR_DEVICE_EXIST -101 +#define ERR_DEVICE_NOT_EXIST -102 +#define ERR_DEVICE_ALREADY_DONE -103 +#define ERR_DEVICE_CONNECT_OTHER -104 + +#define ERR_FILE_OP_FAIL -125 +#define ERR_FILE_EMPTY -126 +#define ERR_FILE_TOO_LARGE -127 +#define ERR_FILE_CONT_TOO_LARGE -128 +#define ERR_FILE_LOCK_FAIL -129 + +#define ERR_PERSIST_NOT_REDHAT -200 + +#endif diff --git a/libnetwork/host_network_helper.c b/libnetwork/host_network_helper.c new file mode 100644 index 0000000..cda2732 --- /dev/null +++ b/libnetwork/host_network_helper.c @@ -0,0 +1,266 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + + + +#include +#include +#include +#include +#include +#include +#include + +#include "host_network_helper.h" +#include "host_network_error.h" + +static int compare_qos_8021q(const void *p1, const void *p2) +{ + const VLAN_Qos_8021q_elem *qos1 = (VLAN_Qos_8021q_elem *)p1; + const VLAN_Qos_8021q_elem *qos2 = (VLAN_Qos_8021q_elem *)p2; + int ret = 0; + if ((qos1->from) > (qos2->from)) { + ret = 1; + } + return ret; +} + +/* it need to be checked see whether these are the conditions */ +int vlan_8021q_qos_check_valid(VLAN_Qos_8021q *pqos) +{ + int ret = 1; + int i = 0; + int last_num = -1; + if ((pqos->count < 0) || (pqos->count > 8)) { + ret = 0; + goto out; + } else if (pqos->count == 0) { + goto out; + } + qsort((void *)pqos->values, pqos->count, sizeof(VLAN_Qos_8021q_elem), + compare_qos_8021q); + + while (i < pqos->count) { + if (pqos->values[i].from == last_num) { + CU_DEBUG("error: vlan 802.1.q qos setting have same values: " + "last is %d, new is %d", last_num, pqos->values[i].from); + ret = 0; + goto out; + } + last_num = pqos->values[i].from; + if ((pqos->values[i].from < 0) || (pqos->values[i].from >= 8)) { + CU_DEBUG("error: vlan 802.1.q qos setting have outbound value: " + "from is %d.", pqos->values[i].from); + ret = 0; + goto out; + } + if ((pqos->values[i].to < 0) || (pqos->values[i].to >= 8)) { + CU_DEBUG("error: vlan 802.1.q qos setting have outbound value: " + "to is %d.", pqos->values[i].to); + ret = 0; + goto out; + } + i++; + } + + out: + return ret; +} + +int vlan_8021q_qos_str_to_num(VLAN_Qos_8021q *pqos, const char* str) +{ + int ret = 1; + char *str_line = NULL; + char *temp; + char *saveptr = NULL; + char *invalptr1, *invalptr2; + int qos_num1, qos_num2; + VLAN_Qos_8021q qos; + + if (str == NULL) { + ret = 0; + goto out; + } + if (str[0] == '\0') { + ret = 1; + pqos->count = 0; + CU_DEBUG("empty vlan 802.1.q qos string found."); + goto out; + } + str_line = SAFE_STRDUP(str); + qos.count = 0; + + temp = strtok_r(str_line, " ", &saveptr); + while (temp != NULL) { + qos_num1 = strtol(temp, &invalptr1, 10); + if (temp == invalptr1) { + ret = 0; + goto out; + } + if (*invalptr1 != ':') { + ret = 0; + goto out; + } + invalptr1++; + qos_num2 = strtol(invalptr1, &invalptr2, 10); + if (invalptr1 == invalptr2) { + ret = 0; + goto out; + } + if (*invalptr2 != '\0') { + ret = 0; + goto out; + } + if (qos.count >= 8) { + ret = 0; + CU_DEBUG("too many settings found in vlan 802.1.q qos string [%s]", + str); + goto out; + } + qos.values[qos.count].from = qos_num1; + qos.values[qos.count].to = qos_num2; + qos.count++; + temp = strtok_r(NULL, " ", &saveptr); + } + ret = vlan_8021q_qos_check_valid(&qos); + if (ret == 1) { + *pqos = qos; + } + + out: + if (ret != 1) { + CU_DEBUG("vlan 802.1.q qos string [%s] is invalid.", str); + } + SAFE_FREE(str_line); + return ret; +} + +int vlan_8021q_qos_num_to_str(char **str, const VLAN_Qos_8021q *pqos) +{ + char temp[16]; + int i; + VLAN_Qos_8021q qos = *pqos; + int ret = vlan_8021q_qos_check_valid(&qos); + if (ret != 1) { + goto out; + } + SAFE_MALLOC(*str, 64); + *str[0] = '\0'; + if (qos.count == 0) { + goto out; + } + i = 0; + snprintf(temp, sizeof(temp), "%d:%d", + qos.values[i].from, qos.values[i].to); + strcat(*str, temp); + i++; + while (i < qos.count) { + strcat(*str, " "); + snprintf(temp, sizeof(temp), "%d:%d", + qos.values[i].from, qos.values[i].to); + strcat(*str, temp); + i++; + } + + out: + return ret; +} + +char *combine_file_name(const char *prefix, const char *name) +{ + char *ret = NULL; + int size; + size = strlen(prefix) + strlen(name) + 1; + SAFE_CALLOC(ret, size, sizeof(char)); + snprintf(ret, size, "%s%s", prefix, name); + return ret; +} + +char *translate_error_no(int errno) +{ + char *ret = NULL; + switch (errno) { + case ERR_REQUEST_NOT_SUPPORT: + ret = "request is not supported now"; + break; + + case ERR_LIBNETLINK: + ret = "error happend in netlink."; + break; + case ERR_LIBBR: + ret = "error happend in bridge commands."; + break; + + case ERR_DEVICE_EXCEED_MAXNUM: + ret = "too many devices found or set, check the environment."; + break; + case ERR_DEVICE_EXIST: + ret = "device already exist, can not execute the command."; + break; + case ERR_DEVICE_NOT_EXIST: + ret = "device do not exist, can not execute the command."; + break; + case ERR_DEVICE_ALREADY_DONE: + ret = "the operation you want have been done before, " + "will not do it again."; + break; + case ERR_DEVICE_CONNECT_OTHER: + ret = "the device you want to connect have been connect to another" + " device, can't change it directly."; + break; + + case ERR_FILE_OP_FAIL: + ret = "failed in accessing the file."; + break; + case ERR_FILE_EMPTY: + ret = "the file it want is empty."; + break; + case ERR_FILE_TOO_LARGE: + ret = "the file it want is too large."; + break; + case ERR_FILE_CONT_TOO_LARGE: + ret = "the content it want to combine to file is too large."; + break; + case ERR_FILE_LOCK_FAIL: + ret = "failed in locking the file, " + "check if other process is using it."; + break; + + case ERR_PERSIST_NOT_REDHAT: + ret = "host is not a RedHat distribution, can't persist the " + "configuration, it would not take effect after host is " + "rebooted. Other version would be supported in the future. " + "If you are sure host is RedHat, make sure command " + " could work."; + break; + + default: + ret = "internal error."; + break; + } + return ret; +} + +int get_simple_state(struct EthIface *piface) +{ + if ((piface->eth_type & ETH_TYPE_ETHER_ANY) && + (piface->eth_type & ETH_TYPE_ETHER_SUB_BRIDGE)) { + if (piface->run_prop.status == IF_OPER_UNKNOWN) { + return 1; + } + } + if (piface->run_prop.status == IF_OPER_UP) { + return 1; + } else { + return 0; + } +} diff --git a/libnetwork/host_network_helper.h b/libnetwork/host_network_helper.h new file mode 100644 index 0000000..fea4f05 --- /dev/null +++ b/libnetwork/host_network_helper.h @@ -0,0 +1,177 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + + +#ifndef HOST_NETWORK_HELPER_H +#define HOST_NETWORK_HELPER_H + +#include +#include +#include + +#include "dll_magic.h" +#include "host_network_basic.h" + +#ifdef TESTLIB +#include "TestDefines.h" +#else +#include +#endif + +#define CMD_DEBUG_LEVEL 2 + +/* macro functions */ +#define CMD_DEBUG(lvl, fmt, args...) do { \ + if (CMD_DEBUG_LEVEL && (lvl) <= CMD_DEBUG_LEVEL) { \ + debug_print(fmt, ##args); \ + } \ +} while (0) + +#define SAFE_MALLOC(p, size) \ +{ \ + (p) = malloc((size)); \ + if ((p) == NULL) { \ + CU_DEBUG("malloc failed."); \ + } \ +} + +#define SAFE_CALLOC(p, nmen, size) \ +{ \ + (p) = calloc((nmen), (size)); \ + if ((p) == NULL) { \ + CU_DEBUG("calloc failed."); \ + } \ +} + +#define SAFE_FREE(p) {free(p); (p) = NULL; } + + +/* Macro used to compare two char*, it would skip if ref is NULL. It would + only set the result when src != ref, user need to set the result to 1 by + default before use the macro. If not set, the it could be used to do + check multi times in "one fail all die" mode. Empty lines is the place + where result should be set to 1. */ +#define CHARS_COMPARE_BY_REF(src, ref, result) do { \ + if ((ref) == NULL) { \ + ; \ + } else { \ + if ((src) == NULL) { \ + (result) = 0; \ + } else { \ + if (0 == strcmp((src), (ref))) { \ + ; \ + } else { \ + (result) = 0; \ + } \ + } \ + } \ +} while (0) + +/* ignore case version */ +#define CHARS_COMPARE_CASE_BY_REF(src, ref, result) do { \ + if ((ref) == NULL) { \ + ; \ + } else { \ + if ((src) == NULL) { \ + (result) = 0; \ + } else { \ + if (0 == strcasecmp((src), (ref))) { \ + ; \ + } else { \ + (result) = 0; \ + } \ + } \ + } \ +} while (0) + +/* compare the value if ref != default */ +#define NUM_COMPARE_BY_REF(src, ref, result, default) do { \ + if ((ref) == (default)) { \ + ; \ + } else { \ + if ((src) == (ref)) { \ + ; \ + } else { \ + result = 0; \ + } \ + } \ +} while (0) + +/* merge the char* string to dest, only when dest == NULL */ +#define CHARS_MERGE_NORMAL(dest, src) do { \ + if (((dest) == NULL) && ((src) != NULL)) { \ + (dest) = strdup((src)); \ + } \ +} while (0) + +/* merge the char* string to dest, only when dest == NULL, + pointer is moved instead of strdup */ +#define CHARS_MERGE_MOVE(dest, src) do { \ + if (((dest) == NULL) && ((src) != NULL)) { \ + (dest) = (src); \ + (src) = NULL; \ + } \ +} while (0) + +/* merge the value, only when dest == default */ +#define NUM_MERGE(dest, src, default) do { \ + if ((dest) == (default)) { \ + (dest) = (src); \ + } \ +} while (0) + +/* this macro may cause "p" to be excuted twice if it is a function */ +#define SAFE_STRDUP(p) (p) == NULL ? NULL : strdup(p); + +/* this macro make sure "src" to be excuted once if it is function, so it is + safe for functions that have state logged, such as "strtok" */ +#define SAFE_STRDUP_WITH_FUNC(dest, src, iter) do { \ + (iter) = (src); \ + if ((iter) == NULL) { \ + (dest) = NULL; \ + } else { \ + (dest) = strdup((iter)); \ + } \ +} while (0) + +/* array version of SAFE_STRDUP, dest and src are char**. */ +#define SAFE_PSTR_ARRAY_DUP(ppdest, dest_num, ppsrc, src_num, iter) do { \ + (dest_num) = (src_num); \ + (ppdest) = NULL; \ + if (((ppsrc) != NULL) && ((src_num) > 0)) { \ + SAFE_CALLOC((ppdest), (src_num), sizeof(char *)); \ + (iter) = 0; \ + while ((iter) < (src_num)) { \ + *((ppdest)+(iter)) = SAFE_STRDUP(*((ppsrc)+(iter))); \ + (iter)++; \ + } \ + } \ +} while (0) + +/* this function would sort the pqos and check its values. */ +int vlan_8021q_qos_check_valid(VLAN_Qos_8021q *pqos); + +/* converting qos string of 802.1.Q, it should be as "0:0 1:0 2:0" */ +DLL_PUBLIC int vlan_8021q_qos_str_to_num(VLAN_Qos_8021q *pqos, const char *str); +DLL_PUBLIC int vlan_8021q_qos_num_to_str(char **str, const VLAN_Qos_8021q *pqos); + +/* following functions would return string by malloc, so it need free later */ +char *combine_file_name(const char *prefix, const char *name); + +/* translate the iffstate to simple down or up, because orginal state is + complex for history reason in linux kernel */ +DLL_PUBLIC int get_simple_state(struct EthIface *piface); + +/* err message number to char* */ +char *translate_error_no(int errno); + +#endif -- 1.7.1 From xiawenc at linux.vnet.ibm.com Wed Jan 18 09:43:02 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Wed, 18 Jan 2012 17:43:02 +0800 Subject: [Libvirt-cim] [V4 PATCH 7/8] vlan library - add interface for CIM model code Message-ID: <1326879782-12392-1-git-send-email-xiawenc@linux.vnet.ibm.com> This patch simple add APIs. Signed-off-by: Wenchao Xia --- libnetwork/host_network_API.c | 30 ++++++++++++++++++++++++++++++ libnetwork/host_network_API.h | 25 +++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 0 deletions(-) create mode 100644 libnetwork/host_network_API.c create mode 100644 libnetwork/host_network_API.h diff --git a/libnetwork/host_network_API.c b/libnetwork/host_network_API.c new file mode 100644 index 0000000..975dbda --- /dev/null +++ b/libnetwork/host_network_API.c @@ -0,0 +1,30 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + + +#include "host_network_API.h" +#include "host_network_implement_OSAPI.h" +#include "host_network_error.h" + +/* this layer is added to devide the abstraction and implemention, so that + different implemention could be used and switched */ + +int get_host_ifaces(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque) +{ + return get_host_eth_ifaces_osapi(plist, filter_func, filter_opaque); +} + +char *get_host_iface_error_reason(int errno) +{ + return translate_error_no(errno); +} diff --git a/libnetwork/host_network_API.h b/libnetwork/host_network_API.h new file mode 100644 index 0000000..e3732a4 --- /dev/null +++ b/libnetwork/host_network_API.h @@ -0,0 +1,25 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#ifndef HOST_NETWORK_API +#define HOST_NETWORK_API + +#include "dll_magic.h" +#include "host_network_basic.h" +#include "host_network_helper.h" + +DLL_PUBLIC int get_host_ifaces(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque); + +DLL_PUBLIC char *get_host_iface_error_reason(int errno); + +#endif -- 1.7.1 From xiawenc at linux.vnet.ibm.com Wed Jan 18 09:43:24 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Wed, 18 Jan 2012 17:43:24 +0800 Subject: [Libvirt-cim] [V4 PATCH 8/8] vlan library - testing program for libnetwork Message-ID: <1326879804-12423-1-git-send-email-xiawenc@linux.vnet.ibm.com> Provide a pure C test program employing libnetwork. Note it is linked with libcmpiutil, so need CU_DEBUG to be set to stdout to see the output. Try vconfig and brctl command modifying the network and then run the test program to see the output. Signed-off-by: Wenchao Xia --- libnetwork/libnetwork_test.c | 91 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 91 insertions(+), 0 deletions(-) create mode 100644 libnetwork/libnetwork_test.c diff --git a/libnetwork/libnetwork_test.c b/libnetwork/libnetwork_test.c new file mode 100644 index 0000000..a611846 --- /dev/null +++ b/libnetwork/libnetwork_test.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "host_network_API.h" + +static long print_and_ret_time_stamp(void) +{ + struct timeval tv; + long ret; + gettimeofday(&tv, NULL); + ret = tv.tv_sec*1000+ tv.tv_usec/1000; + printf("time is [%ld] ms.", ret); + return ret; +} + +int main(int argc, char **argv) +{ + EthIfacesList ifaces_list; + EthIface iface_ref,iface_br,iface_vlan; + int comp_ret = 0; + int persist_flag = 1; + long timestart, timeend; + int i; + + + printf("executing the program with persist flag %d.\n", persist_flag); + comp_ret = 0; + + eth_ifaceslist_init(&ifaces_list); + eth_iface_init(&iface_ref); + eth_iface_init(&iface_br); + eth_iface_init(&iface_vlan); + + eth_iface_add_br_prop(&iface_br); + eth_iface_add_vlan_prop(&iface_vlan, VLAN_TYPE_802_1_Q); + iface_br.eth_type = ETH_TYPE_ETHER_SUB_BRIDGE | ETH_TYPE_ETHER_ANY; + iface_vlan.eth_type = ETH_TYPE_ETHER_SUB_VLAN | ETH_TYPE_ETHER_ANY; + + //iface_ref.name = SAFE_STRDUP("eth1.100"); + iface_ref.eth_type = ETH_TYPE_ETHER_SUB_BRIDGE | ETH_TYPE_ETHER_ANY; + + iface_br.name = SAFE_STRDUP("test_br"); + iface_vlan.name = SAFE_STRDUP("eth0.1000"); + + iface_br.pbr_prop->STP = 1; + + iface_vlan.pvlan_prop->vlan_type = VLAN_TYPE_802_1_Q; + iface_vlan.pvlan_prop->props.prop_8021q.parent = SAFE_STRDUP("eth0"); + iface_vlan.pvlan_prop->props.prop_8021q.vlan_id = 1000; + iface_vlan.pvlan_prop->props.prop_8021q.reorder_hdr = 0; + iface_vlan.pvlan_prop->props.prop_8021q.ingress.count = 1; + iface_vlan.pvlan_prop->props.prop_8021q.ingress.values[0].from = 2; + iface_vlan.pvlan_prop->props.prop_8021q.ingress.values[0].to = 3; + iface_vlan.pvlan_prop->props.prop_8021q.egress.count = 1; + iface_vlan.pvlan_prop->props.prop_8021q.egress.values[0].from = 4; + iface_vlan.pvlan_prop->props.prop_8021q.egress.values[0].to = 6; + + timestart = print_and_ret_time_stamp(); + printf(" start list the host ifaces.\n"); + + get_host_ifaces(&ifaces_list, NULL, NULL); + //get_host_ifaces(&ifaces_list, eth_iface_filter_by_ref, &iface_ref); + //get_host_ifaces(&ifaces_list, eth_iface_filter_vlans, NULL); + //get_host_ifaces(&ifaces_list, eth_iface_filter_peths, NULL); + + timeend = print_and_ret_time_stamp(); + printf(" end list the host ifaces, cost [%ld]ms.\n", timeend-timestart); + + eth_ifaceslist_print(&ifaces_list); + eth_ifaceslist_uninit(&ifaces_list); + + /* test for mem leak */ +/* + for (i = 0; i < 10; i++) { + eth_ifaceslist_init(&ifaces_list); + get_host_ifaces(&ifaces_list, NULL, NULL); + eth_ifaceslist_uninit(&ifaces_list); + } +*/ + eth_iface_uninit(&iface_ref); + eth_iface_uninit(&iface_br); + eth_iface_uninit(&iface_vlan); + + return 0; +} -- 1.7.1 From xiawenc at linux.vnet.ibm.com Wed Jan 18 10:10:24 2012 From: xiawenc at linux.vnet.ibm.com (Wayne Xia) Date: Wed, 18 Jan 2012 18:10:24 +0800 Subject: [Libvirt-cim] [PATCH v3 00/10] VLAN extension - ReadOnly functions In-Reply-To: <4F15A24D.4040206@linux.vnet.ibm.com> References: <1326361614-18674-1-git-send-email-xiawenc@linux.vnet.ibm.com> <4F15A24D.4040206@linux.vnet.ibm.com> Message-ID: <4F169A90.9050000@linux.vnet.ibm.com> ? 2012-1-18 0:31, Chip Vincent ??: > Just a nit: The copyrights at the top of source files you've written > should now be 2012. I'm in the process of a deeper review of the rest of > the code and will respond soon. > V4 patch for latest libvirt-cim were sent, it just added the library and have less code easier to view. :) > On 01/12/2012 04:46 AM, Wayne Xia wrote: >> These patches would try introduce 4 class with readonly functionality. >> It used libnl-3 and libbridge as static libarary as an implemention. >> Program libnetwork_test would be generated under ./libnetwork/.libs/ . >> Testing: >> wbemcli -nl ein >> http://[]:[]@localhost:5988/root/virt:Net_VirtualEthernetSwitchSystem >> wbemcli -nl ein >> http://[]:[]@localhost:5988/root/virt:Net_VirtualEthernetSwitchSystemSettingData >> >> wbemcli -nl ein http://[]:[]@localhost:5988/root/virt:Net_EthernetPort >> wbemcli -nl ein >> http://[]:[]@localhost:5988/root/virt:Net_EthernetPortAllocationSettingData >> >> try with command vconfig and brctl modifying the system. >> Note: >> These patch only applys on libvirt-cim-0.5.15, Will try move it to 0.6.0 >> with libvirt 0.9.4 on RH6 on v4 patch. >> >> repository: >> git://gitorious.org/~xiaxia347/libvirt-cim/xiaxia347s-xiawenc.git >> branch vlan_v3 >> https://gitorious.org/libvirt-cim/xiaxia347s-xiawenc/trees/vlan_v3 >> >> >> Wayne Xia (10): >> add source code of libbridge and libnl-3 >> building system modification for libnl3 and libbridge >> building system of libnetwork linking with libnl3 and libbridge >> libnetwork source code with a test program >> add a CIM model helper in libxkutil >> CIM model - Makefile change >> CIM model - VESS >> CIM model - VESSSD >> CIM model - EthernetPort >> CIM model - EASD >> >> Makefile.am | 14 +- >> configure.ac | 19 +- >> libnetwork/Makefile.am | 39 + >> libnetwork/dll_magic.h | 13 + >> libnetwork/host_network_API.c | 30 + >> libnetwork/host_network_API.h | 25 + >> libnetwork/host_network_basic.c | 657 ++++++ >> libnetwork/host_network_basic.h | 170 ++ >> libnetwork/host_network_error.h | 31 + >> libnetwork/host_network_helper.c | 659 ++++++ >> libnetwork/host_network_helper.h | 202 ++ >> libnetwork/host_network_implement_OSAPI.c | 453 ++++ >> libnetwork/host_network_implement_OSAPI.h | 21 + >> libnetwork/libbridge/.gitignore | 2 + >> libnetwork/libbridge/Makefile.am | 20 + >> libnetwork/libbridge/libbridge.h | 119 + >> libnetwork/libbridge/libbridge_devif.c | 442 ++++ >> libnetwork/libbridge/libbridge_if.c | 117 + >> libnetwork/libbridge/libbridge_init.c | 213 ++ >> libnetwork/libbridge/libbridge_misc.c | 51 + >> libnetwork/libbridge/libbridge_private.h | 56 + >> libnetwork/libnetwork_test.c | 82 + >> libnetwork/libnl3/Makefile.am | 8 + >> libnetwork/libnl3/include/Makefile.am | 122 + >> libnetwork/libnl3/include/linux/fib_rules.h | 69 + >> libnetwork/libnl3/include/linux/gen_stats.h | 67 + >> libnetwork/libnl3/include/linux/genetlink.h | 83 + >> libnetwork/libnl3/include/linux/if.h | 140 ++ >> libnetwork/libnl3/include/linux/if_addr.h | 55 + >> libnetwork/libnl3/include/linux/if_arp.h | 156 ++ >> libnetwork/libnl3/include/linux/if_ether.h | 125 ++ >> libnetwork/libnl3/include/linux/if_link.h | 377 ++++ >> libnetwork/libnl3/include/linux/if_vlan.h | 62 + >> libnetwork/libnl3/include/linux/inetdevice.h | 36 + >> libnetwork/libnl3/include/linux/ip_mp_alg.h | 22 + >> libnetwork/libnl3/include/linux/ipv6.h | 146 ++ >> libnetwork/libnl3/include/linux/neighbour.h | 155 ++ >> libnetwork/libnl3/include/linux/netfilter.h | 57 + >> .../libnl3/include/linux/netfilter/nfnetlink.h | 60 + >> .../include/linux/netfilter/nfnetlink_conntrack.h | 140 ++ >> .../libnl3/include/linux/netfilter/nfnetlink_log.h | 97 + >> .../include/linux/netfilter/nfnetlink_queue.h | 94 + >> libnetwork/libnl3/include/linux/netlink.h | 149 ++ >> libnetwork/libnl3/include/linux/pkt_cls.h | 467 ++++ >> libnetwork/libnl3/include/linux/pkt_sched.h | 606 +++++ >> libnetwork/libnl3/include/linux/rtnetlink.h | 605 +++++ >> libnetwork/libnl3/include/linux/snmp.h | 270 +++ >> .../libnl3/include/linux/tc_ematch/tc_em_meta.h | 89 + >> libnetwork/libnl3/include/netlink-generic.h | 20 + >> libnetwork/libnl3/include/netlink-local.h | 213 ++ >> libnetwork/libnl3/include/netlink-tc.h | 55 + >> libnetwork/libnl3/include/netlink-types.h | 846 +++++++ >> libnetwork/libnl3/include/netlink/addr.h | 66 + >> libnetwork/libnl3/include/netlink/attr.h | 283 +++ >> libnetwork/libnl3/include/netlink/cache-api.h | 230 ++ >> libnetwork/libnl3/include/netlink/cache.h | 134 ++ >> libnetwork/libnl3/include/netlink/cli/addr.h | 32 + >> libnetwork/libnl3/include/netlink/cli/class.h | 21 + >> libnetwork/libnl3/include/netlink/cli/cls.h | 24 + >> libnetwork/libnl3/include/netlink/cli/ct.h | 34 + >> libnetwork/libnl3/include/netlink/cli/link.h | 30 + >> libnetwork/libnl3/include/netlink/cli/neigh.h | 27 + >> libnetwork/libnl3/include/netlink/cli/qdisc.h | 23 + >> libnetwork/libnl3/include/netlink/cli/route.h | 34 + >> libnetwork/libnl3/include/netlink/cli/rule.h | 21 + >> libnetwork/libnl3/include/netlink/cli/tc.h | 39 + >> libnetwork/libnl3/include/netlink/cli/utils.h | 82 + >> libnetwork/libnl3/include/netlink/data.h | 41 + >> libnetwork/libnl3/include/netlink/errno.h | 64 + >> .../libnl3/include/netlink/fib_lookup/lookup.h | 42 + >> .../libnl3/include/netlink/fib_lookup/request.h | 51 + >> libnetwork/libnl3/include/netlink/genl/ctrl.h | 40 + >> libnetwork/libnl3/include/netlink/genl/family.h | 53 + >> libnetwork/libnl3/include/netlink/genl/genl.h | 46 + >> libnetwork/libnl3/include/netlink/genl/mngt.h | 87 + >> libnetwork/libnl3/include/netlink/handlers.h | 146 ++ >> libnetwork/libnl3/include/netlink/list.h | 93 + >> libnetwork/libnl3/include/netlink/msg.h | 147 ++ >> libnetwork/libnl3/include/netlink/netfilter/ct.h | 126 ++ >> libnetwork/libnl3/include/netlink/netfilter/log.h | 109 + >> .../libnl3/include/netlink/netfilter/log_msg.h | 98 + >> .../libnl3/include/netlink/netfilter/netfilter.h | 31 + >> libnetwork/libnl3/include/netlink/netfilter/nfnl.h | 44 + >> .../libnl3/include/netlink/netfilter/queue.h | 90 + >> .../libnl3/include/netlink/netfilter/queue_msg.h | 104 + >> libnetwork/libnl3/include/netlink/netlink-compat.h | 50 + >> libnetwork/libnl3/include/netlink/netlink-kernel.h | 293 +++ >> libnetwork/libnl3/include/netlink/netlink.h | 93 + >> libnetwork/libnl3/include/netlink/object-api.h | 348 +++ >> libnetwork/libnl3/include/netlink/object.h | 70 + >> libnetwork/libnl3/include/netlink/route/addr.h | 98 + >> libnetwork/libnl3/include/netlink/route/class.h | 66 + >> .../libnl3/include/netlink/route/classifier.h | 51 + >> .../libnl3/include/netlink/route/cls/basic.h | 31 + >> .../libnl3/include/netlink/route/cls/cgroup.h | 30 + >> .../libnl3/include/netlink/route/cls/ematch.h | 95 + >> .../libnl3/include/netlink/route/cls/ematch/cmp.h | 32 + >> .../libnl3/include/netlink/route/cls/ematch/meta.h | 41 + >> .../include/netlink/route/cls/ematch/nbyte.h | 36 + >> .../libnl3/include/netlink/route/cls/ematch/text.h | 42 + >> libnetwork/libnl3/include/netlink/route/cls/fw.h | 29 + >> .../libnl3/include/netlink/route/cls/police.h | 29 + >> libnetwork/libnl3/include/netlink/route/cls/u32.h | 43 + >> libnetwork/libnl3/include/netlink/route/link.h | 217 ++ >> libnetwork/libnl3/include/netlink/route/link/api.h | 134 ++ >> .../libnl3/include/netlink/route/link/bonding.h | 37 + >> .../libnl3/include/netlink/route/link/inet.h | 29 + >> .../libnl3/include/netlink/route/link/info-api.h | 20 + >> .../libnl3/include/netlink/route/link/vlan.h | 57 + >> .../libnl3/include/netlink/route/neighbour.h | 79 + >> libnetwork/libnl3/include/netlink/route/neightbl.h | 65 + >> libnetwork/libnl3/include/netlink/route/nexthop.h | 65 + >> libnetwork/libnl3/include/netlink/route/pktloc.h | 49 + >> libnetwork/libnl3/include/netlink/route/qdisc.h | 73 + >> .../libnl3/include/netlink/route/qdisc/cbq.h | 30 + >> .../libnl3/include/netlink/route/qdisc/dsmark.h | 41 + >> .../libnl3/include/netlink/route/qdisc/fifo.h | 28 + >> .../libnl3/include/netlink/route/qdisc/htb.h | 47 + >> .../libnl3/include/netlink/route/qdisc/netem.h | 75 + >> .../libnl3/include/netlink/route/qdisc/prio.h | 53 + >> .../libnl3/include/netlink/route/qdisc/red.h | 17 + >> .../libnl3/include/netlink/route/qdisc/sfq.h | 36 + >> .../libnl3/include/netlink/route/qdisc/tbf.h | 40 + >> libnetwork/libnl3/include/netlink/route/route.h | 124 + >> libnetwork/libnl3/include/netlink/route/rtnl.h | 69 + >> libnetwork/libnl3/include/netlink/route/rule.h | 75 + >> libnetwork/libnl3/include/netlink/route/tc-api.h | 143 ++ >> libnetwork/libnl3/include/netlink/route/tc.h | 105 + >> libnetwork/libnl3/include/netlink/socket.h | 69 + >> libnetwork/libnl3/include/netlink/types.h | 110 + >> libnetwork/libnl3/include/netlink/utils.h | 85 + >> libnetwork/libnl3/include/netlink/version.h | 28 + >> libnetwork/libnl3/include/netlink/version.h.in | 28 + >> libnetwork/libnl3/lib/Makefile.am | 99 + >> libnetwork/libnl3/lib/addr.c | 918 ++++++++ >> libnetwork/libnl3/lib/attr.c | 1213 ++++++++++ >> libnetwork/libnl3/lib/cache.c | 965 ++++++++ >> libnetwork/libnl3/lib/cache_mngr.c | 391 ++++ >> libnetwork/libnl3/lib/cache_mngt.c | 256 +++ >> libnetwork/libnl3/lib/cli/cls/basic.c | 93 + >> libnetwork/libnl3/lib/cli/cls/cgroup.c | 75 + >> libnetwork/libnl3/lib/cli/qdisc/bfifo.c | 83 + >> libnetwork/libnl3/lib/cli/qdisc/blackhole.c | 64 + >> libnetwork/libnl3/lib/cli/qdisc/htb.c | 203 ++ >> libnetwork/libnl3/lib/cli/qdisc/pfifo.c | 77 + >> libnetwork/libnl3/lib/data.c | 186 ++ >> libnetwork/libnl3/lib/defs.h | 85 + >> libnetwork/libnl3/lib/defs.h.in | 84 + >> libnetwork/libnl3/lib/error.c | 116 + >> libnetwork/libnl3/lib/fib_lookup/lookup.c | 348 +++ >> libnetwork/libnl3/lib/fib_lookup/request.c | 185 ++ >> libnetwork/libnl3/lib/genl/ctrl.c | 380 ++++ >> libnetwork/libnl3/lib/genl/family.c | 316 +++ >> libnetwork/libnl3/lib/genl/genl.c | 268 +++ >> libnetwork/libnl3/lib/genl/mngt.c | 273 +++ >> libnetwork/libnl3/lib/handlers.c | 395 ++++ >> libnetwork/libnl3/lib/msg.c | 1050 +++++++++ >> libnetwork/libnl3/lib/netfilter/ct.c | 601 +++++ >> libnetwork/libnl3/lib/netfilter/ct_obj.c | 785 +++++++ >> libnetwork/libnl3/lib/netfilter/log.c | 251 +++ >> libnetwork/libnl3/lib/netfilter/log_msg.c | 209 ++ >> libnetwork/libnl3/lib/netfilter/log_msg_obj.c | 458 ++++ >> libnetwork/libnl3/lib/netfilter/log_obj.c | 287 +++ >> libnetwork/libnl3/lib/netfilter/netfilter.c | 53 + >> libnetwork/libnl3/lib/netfilter/nfnl.c | 245 ++ >> libnetwork/libnl3/lib/netfilter/queue.c | 251 +++ >> libnetwork/libnl3/lib/netfilter/queue_msg.c | 284 +++ >> libnetwork/libnl3/lib/netfilter/queue_msg_obj.c | 492 ++++ >> libnetwork/libnl3/lib/netfilter/queue_obj.c | 215 ++ >> libnetwork/libnl3/lib/nl.c | 896 ++++++++ >> libnetwork/libnl3/lib/object.c | 395 ++++ >> libnetwork/libnl3/lib/route/addr.c | 1054 +++++++++ >> libnetwork/libnl3/lib/route/class.c | 473 ++++ >> libnetwork/libnl3/lib/route/classid.c | 441 ++++ >> libnetwork/libnl3/lib/route/cls.c | 441 ++++ >> libnetwork/libnl3/lib/route/cls/basic.c | 229 ++ >> libnetwork/libnl3/lib/route/cls/cgroup.c | 189 ++ >> libnetwork/libnl3/lib/route/cls/ematch.c | 701 ++++++ >> libnetwork/libnl3/lib/route/cls/ematch/cmp.c | 93 + >> libnetwork/libnl3/lib/route/cls/ematch/container.c | 41 + >> libnetwork/libnl3/lib/route/cls/ematch/meta.c | 334 +++ >> libnetwork/libnl3/lib/route/cls/ematch/nbyte.c | 139 ++ >> libnetwork/libnl3/lib/route/cls/ematch/text.c | 183 ++ >> libnetwork/libnl3/lib/route/cls/ematch_grammar.l | 162 ++ >> libnetwork/libnl3/lib/route/cls/ematch_syntax.y | 497 +++++ >> libnetwork/libnl3/lib/route/cls/fw.c | 190 ++ >> libnetwork/libnl3/lib/route/cls/police.c | 66 + >> libnetwork/libnl3/lib/route/cls/u32.c | 551 +++++ >> libnetwork/libnl3/lib/route/link.c | 2342 ++++++++++++++++++++ >> libnetwork/libnl3/lib/route/link/api.c | 316 +++ >> libnetwork/libnl3/lib/route/link/bonding.c | 217 ++ >> libnetwork/libnl3/lib/route/link/bridge.c | 83 + >> libnetwork/libnl3/lib/route/link/dummy.c | 40 + >> libnetwork/libnl3/lib/route/link/inet.c | 280 +++ >> libnetwork/libnl3/lib/route/link/inet6.c | 377 ++++ >> libnetwork/libnl3/lib/route/link/vlan.c | 565 +++++ >> libnetwork/libnl3/lib/route/neigh.c | 846 +++++++ >> libnetwork/libnl3/lib/route/neightbl.c | 815 +++++++ >> libnetwork/libnl3/lib/route/nexthop.c | 290 +++ >> libnetwork/libnl3/lib/route/pktloc.c | 260 +++ >> libnetwork/libnl3/lib/route/pktloc_grammar.l | 51 + >> libnetwork/libnl3/lib/route/pktloc_syntax.y | 103 + >> libnetwork/libnl3/lib/route/qdisc.c | 575 +++++ >> libnetwork/libnl3/lib/route/qdisc/blackhole.c | 37 + >> libnetwork/libnl3/lib/route/qdisc/cbq.c | 204 ++ >> libnetwork/libnl3/lib/route/qdisc/dsmark.c | 413 ++++ >> libnetwork/libnl3/lib/route/qdisc/fifo.c | 169 ++ >> libnetwork/libnl3/lib/route/qdisc/htb.c | 643 ++++++ >> libnetwork/libnl3/lib/route/qdisc/netem.c | 906 ++++++++ >> libnetwork/libnl3/lib/route/qdisc/prio.c | 294 +++ >> libnetwork/libnl3/lib/route/qdisc/red.c | 190 ++ >> libnetwork/libnl3/lib/route/qdisc/sfq.c | 256 +++ >> libnetwork/libnl3/lib/route/qdisc/tbf.c | 460 ++++ >> libnetwork/libnl3/lib/route/route.c | 202 ++ >> libnetwork/libnl3/lib/route/route_obj.c | 1148 ++++++++++ >> libnetwork/libnl3/lib/route/route_utils.c | 171 ++ >> libnetwork/libnl3/lib/route/rtnl.c | 124 + >> libnetwork/libnl3/lib/route/rule.c | 753 +++++++ >> libnetwork/libnl3/lib/route/tc.c | 1069 +++++++++ >> libnetwork/libnl3/lib/socket.c | 628 ++++++ >> libnetwork/libnl3/lib/stamp-h1 | 1 + >> libnetwork/libnl3/lib/utils.c | 1040 +++++++++ >> libxkutil/Makefile.am | 12 +- >> libxkutil/network_model_helper.c | 466 ++++ >> libxkutil/network_model_helper.h | 105 + >> schema/EthernetPort.mof | 4 + >> schema/EthernetPort.registration | 3 + >> schema/EthernetPortAllocationSettingData.mof | 21 + >> .../EthernetPortAllocationSettingData.registration | 3 + >> schema/VirtualEthernetSwitchSystem.mof | 10 + >> schema/VirtualEthernetSwitchSystem.registration | 3 + >> schema/VirtualEthernetSwitchSystemSettingData.mof | 27 + >> ...ualEthernetSwitchSystemSettingData.registration | 3 + >> src/Makefile.am | 23 +- >> src/Virt_EASD.c | 729 ++++++ >> src/Virt_EASD.h | 59 + >> src/Virt_EthernetPort.c | 561 +++++ >> src/Virt_EthernetPort.h | 58 + >> src/Virt_VESSSD.c | 372 ++++ >> src/Virt_VESSSD.h | 39 + >> src/Virt_VirtualEthernetSwitchSystem.c | 477 ++++ >> src/Virt_VirtualEthernetSwitchSystem.h | 52 + >> 242 files changed, 53037 insertions(+), 10 deletions(-) >> create mode 100644 libnetwork/Makefile.am >> create mode 100644 libnetwork/dll_magic.h >> create mode 100644 libnetwork/host_network_API.c >> create mode 100644 libnetwork/host_network_API.h >> create mode 100644 libnetwork/host_network_basic.c >> create mode 100644 libnetwork/host_network_basic.h >> create mode 100644 libnetwork/host_network_error.h >> create mode 100644 libnetwork/host_network_helper.c >> create mode 100644 libnetwork/host_network_helper.h >> create mode 100644 libnetwork/host_network_implement_OSAPI.c >> create mode 100644 libnetwork/host_network_implement_OSAPI.h >> create mode 100755 libnetwork/libbridge/.gitignore >> create mode 100644 libnetwork/libbridge/Makefile.am >> create mode 100644 libnetwork/libbridge/libbridge.h >> create mode 100644 libnetwork/libbridge/libbridge_devif.c >> create mode 100644 libnetwork/libbridge/libbridge_if.c >> create mode 100644 libnetwork/libbridge/libbridge_init.c >> create mode 100644 libnetwork/libbridge/libbridge_misc.c >> create mode 100644 libnetwork/libbridge/libbridge_private.h >> create mode 100644 libnetwork/libnetwork_test.c >> create mode 100644 libnetwork/libnl3/Makefile.am >> create mode 100644 libnetwork/libnl3/include/Makefile.am >> create mode 100644 libnetwork/libnl3/include/linux/fib_rules.h >> create mode 100644 libnetwork/libnl3/include/linux/gen_stats.h >> create mode 100644 libnetwork/libnl3/include/linux/genetlink.h >> create mode 100644 libnetwork/libnl3/include/linux/if.h >> create mode 100644 libnetwork/libnl3/include/linux/if_addr.h >> create mode 100644 libnetwork/libnl3/include/linux/if_arp.h >> create mode 100644 libnetwork/libnl3/include/linux/if_ether.h >> create mode 100644 libnetwork/libnl3/include/linux/if_link.h >> create mode 100644 libnetwork/libnl3/include/linux/if_vlan.h >> create mode 100644 libnetwork/libnl3/include/linux/inetdevice.h >> create mode 100644 libnetwork/libnl3/include/linux/ip_mp_alg.h >> create mode 100644 libnetwork/libnl3/include/linux/ipv6.h >> create mode 100644 libnetwork/libnl3/include/linux/neighbour.h >> create mode 100644 libnetwork/libnl3/include/linux/netfilter.h >> create mode 100644 libnetwork/libnl3/include/linux/netfilter/nfnetlink.h >> create mode 100644 >> libnetwork/libnl3/include/linux/netfilter/nfnetlink_conntrack.h >> create mode 100644 >> libnetwork/libnl3/include/linux/netfilter/nfnetlink_log.h >> create mode 100644 >> libnetwork/libnl3/include/linux/netfilter/nfnetlink_queue.h >> create mode 100644 libnetwork/libnl3/include/linux/netlink.h >> create mode 100644 libnetwork/libnl3/include/linux/pkt_cls.h >> create mode 100644 libnetwork/libnl3/include/linux/pkt_sched.h >> create mode 100644 libnetwork/libnl3/include/linux/rtnetlink.h >> create mode 100644 libnetwork/libnl3/include/linux/snmp.h >> create mode 100644 libnetwork/libnl3/include/linux/tc_ematch/tc_em_meta.h >> create mode 100644 libnetwork/libnl3/include/netlink-generic.h >> create mode 100644 libnetwork/libnl3/include/netlink-local.h >> create mode 100644 libnetwork/libnl3/include/netlink-tc.h >> create mode 100644 libnetwork/libnl3/include/netlink-types.h >> create mode 100644 libnetwork/libnl3/include/netlink/addr.h >> create mode 100644 libnetwork/libnl3/include/netlink/attr.h >> create mode 100644 libnetwork/libnl3/include/netlink/cache-api.h >> create mode 100644 libnetwork/libnl3/include/netlink/cache.h >> create mode 100644 libnetwork/libnl3/include/netlink/cli/addr.h >> create mode 100644 libnetwork/libnl3/include/netlink/cli/class.h >> create mode 100644 libnetwork/libnl3/include/netlink/cli/cls.h >> create mode 100644 libnetwork/libnl3/include/netlink/cli/ct.h >> create mode 100644 libnetwork/libnl3/include/netlink/cli/link.h >> create mode 100644 libnetwork/libnl3/include/netlink/cli/neigh.h >> create mode 100644 libnetwork/libnl3/include/netlink/cli/qdisc.h >> create mode 100644 libnetwork/libnl3/include/netlink/cli/route.h >> create mode 100644 libnetwork/libnl3/include/netlink/cli/rule.h >> create mode 100644 libnetwork/libnl3/include/netlink/cli/tc.h >> create mode 100644 libnetwork/libnl3/include/netlink/cli/utils.h >> create mode 100644 libnetwork/libnl3/include/netlink/data.h >> create mode 100644 libnetwork/libnl3/include/netlink/errno.h >> create mode 100644 libnetwork/libnl3/include/netlink/fib_lookup/lookup.h >> create mode 100644 libnetwork/libnl3/include/netlink/fib_lookup/request.h >> create mode 100644 libnetwork/libnl3/include/netlink/genl/ctrl.h >> create mode 100644 libnetwork/libnl3/include/netlink/genl/family.h >> create mode 100644 libnetwork/libnl3/include/netlink/genl/genl.h >> create mode 100644 libnetwork/libnl3/include/netlink/genl/mngt.h >> create mode 100644 libnetwork/libnl3/include/netlink/handlers.h >> create mode 100644 libnetwork/libnl3/include/netlink/list.h >> create mode 100644 libnetwork/libnl3/include/netlink/msg.h >> create mode 100644 libnetwork/libnl3/include/netlink/netfilter/ct.h >> create mode 100644 libnetwork/libnl3/include/netlink/netfilter/log.h >> create mode 100644 libnetwork/libnl3/include/netlink/netfilter/log_msg.h >> create mode 100644 >> libnetwork/libnl3/include/netlink/netfilter/netfilter.h >> create mode 100644 libnetwork/libnl3/include/netlink/netfilter/nfnl.h >> create mode 100644 libnetwork/libnl3/include/netlink/netfilter/queue.h >> create mode 100644 >> libnetwork/libnl3/include/netlink/netfilter/queue_msg.h >> create mode 100644 libnetwork/libnl3/include/netlink/netlink-compat.h >> create mode 100644 libnetwork/libnl3/include/netlink/netlink-kernel.h >> create mode 100644 libnetwork/libnl3/include/netlink/netlink.h >> create mode 100644 libnetwork/libnl3/include/netlink/object-api.h >> create mode 100644 libnetwork/libnl3/include/netlink/object.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/addr.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/class.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/classifier.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/cls/basic.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/cls/cgroup.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/cls/ematch.h >> create mode 100644 >> libnetwork/libnl3/include/netlink/route/cls/ematch/cmp.h >> create mode 100644 >> libnetwork/libnl3/include/netlink/route/cls/ematch/meta.h >> create mode 100644 >> libnetwork/libnl3/include/netlink/route/cls/ematch/nbyte.h >> create mode 100644 >> libnetwork/libnl3/include/netlink/route/cls/ematch/text.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/cls/fw.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/cls/police.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/cls/u32.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/link.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/link/api.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/link/bonding.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/link/inet.h >> create mode 100644 >> libnetwork/libnl3/include/netlink/route/link/info-api.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/link/vlan.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/neighbour.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/neightbl.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/nexthop.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/pktloc.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/cbq.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/dsmark.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/fifo.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/htb.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/netem.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/prio.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/red.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/sfq.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/qdisc/tbf.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/route.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/rtnl.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/rule.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/tc-api.h >> create mode 100644 libnetwork/libnl3/include/netlink/route/tc.h >> create mode 100644 libnetwork/libnl3/include/netlink/socket.h >> create mode 100644 libnetwork/libnl3/include/netlink/types.h >> create mode 100644 libnetwork/libnl3/include/netlink/utils.h >> create mode 100644 libnetwork/libnl3/include/netlink/version.h >> create mode 100644 libnetwork/libnl3/include/netlink/version.h.in >> create mode 100644 libnetwork/libnl3/lib/Makefile.am >> create mode 100644 libnetwork/libnl3/lib/addr.c >> create mode 100644 libnetwork/libnl3/lib/attr.c >> create mode 100644 libnetwork/libnl3/lib/cache.c >> create mode 100644 libnetwork/libnl3/lib/cache_mngr.c >> create mode 100644 libnetwork/libnl3/lib/cache_mngt.c >> create mode 100644 libnetwork/libnl3/lib/cli/cls/.dirstamp >> create mode 100644 libnetwork/libnl3/lib/cli/cls/basic.c >> create mode 100644 libnetwork/libnl3/lib/cli/cls/cgroup.c >> create mode 100644 libnetwork/libnl3/lib/cli/qdisc/.dirstamp >> create mode 100644 libnetwork/libnl3/lib/cli/qdisc/bfifo.c >> create mode 100644 libnetwork/libnl3/lib/cli/qdisc/blackhole.c >> create mode 100644 libnetwork/libnl3/lib/cli/qdisc/htb.c >> create mode 100644 libnetwork/libnl3/lib/cli/qdisc/pfifo.c >> create mode 100644 libnetwork/libnl3/lib/data.c >> create mode 100644 libnetwork/libnl3/lib/defs.h >> create mode 100644 libnetwork/libnl3/lib/defs.h.in >> create mode 100644 libnetwork/libnl3/lib/error.c >> create mode 100644 libnetwork/libnl3/lib/fib_lookup/.dirstamp >> create mode 100644 libnetwork/libnl3/lib/fib_lookup/lookup.c >> create mode 100644 libnetwork/libnl3/lib/fib_lookup/request.c >> create mode 100644 libnetwork/libnl3/lib/genl/.dirstamp >> create mode 100644 libnetwork/libnl3/lib/genl/ctrl.c >> create mode 100644 libnetwork/libnl3/lib/genl/family.c >> create mode 100644 libnetwork/libnl3/lib/genl/genl.c >> create mode 100644 libnetwork/libnl3/lib/genl/mngt.c >> create mode 100644 libnetwork/libnl3/lib/handlers.c >> create mode 100644 libnetwork/libnl3/lib/msg.c >> create mode 100644 libnetwork/libnl3/lib/netfilter/.dirstamp >> create mode 100644 libnetwork/libnl3/lib/netfilter/ct.c >> create mode 100644 libnetwork/libnl3/lib/netfilter/ct_obj.c >> create mode 100644 libnetwork/libnl3/lib/netfilter/log.c >> create mode 100644 libnetwork/libnl3/lib/netfilter/log_msg.c >> create mode 100644 libnetwork/libnl3/lib/netfilter/log_msg_obj.c >> create mode 100644 libnetwork/libnl3/lib/netfilter/log_obj.c >> create mode 100644 libnetwork/libnl3/lib/netfilter/netfilter.c >> create mode 100644 libnetwork/libnl3/lib/netfilter/nfnl.c >> create mode 100644 libnetwork/libnl3/lib/netfilter/queue.c >> create mode 100644 libnetwork/libnl3/lib/netfilter/queue_msg.c >> create mode 100644 libnetwork/libnl3/lib/netfilter/queue_msg_obj.c >> create mode 100644 libnetwork/libnl3/lib/netfilter/queue_obj.c >> create mode 100644 libnetwork/libnl3/lib/nl.c >> create mode 100644 libnetwork/libnl3/lib/object.c >> create mode 100644 libnetwork/libnl3/lib/route/.dirstamp >> create mode 100644 libnetwork/libnl3/lib/route/addr.c >> create mode 100644 libnetwork/libnl3/lib/route/class.c >> create mode 100644 libnetwork/libnl3/lib/route/classid.c >> create mode 100644 libnetwork/libnl3/lib/route/cls.c >> create mode 100644 libnetwork/libnl3/lib/route/cls/.dirstamp >> create mode 100644 libnetwork/libnl3/lib/route/cls/basic.c >> create mode 100644 libnetwork/libnl3/lib/route/cls/cgroup.c >> create mode 100644 libnetwork/libnl3/lib/route/cls/ematch.c >> create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/.dirstamp >> create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/cmp.c >> create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/container.c >> create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/meta.c >> create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/nbyte.c >> create mode 100644 libnetwork/libnl3/lib/route/cls/ematch/text.c >> create mode 100644 libnetwork/libnl3/lib/route/cls/ematch_grammar.l >> create mode 100644 libnetwork/libnl3/lib/route/cls/ematch_syntax.y >> create mode 100644 libnetwork/libnl3/lib/route/cls/fw.c >> create mode 100644 libnetwork/libnl3/lib/route/cls/police.c >> create mode 100644 libnetwork/libnl3/lib/route/cls/u32.c >> create mode 100644 libnetwork/libnl3/lib/route/link.c >> create mode 100644 libnetwork/libnl3/lib/route/link/.dirstamp >> create mode 100644 libnetwork/libnl3/lib/route/link/api.c >> create mode 100644 libnetwork/libnl3/lib/route/link/bonding.c >> create mode 100644 libnetwork/libnl3/lib/route/link/bridge.c >> create mode 100644 libnetwork/libnl3/lib/route/link/dummy.c >> create mode 100644 libnetwork/libnl3/lib/route/link/inet.c >> create mode 100644 libnetwork/libnl3/lib/route/link/inet6.c >> create mode 100644 libnetwork/libnl3/lib/route/link/vlan.c >> create mode 100644 libnetwork/libnl3/lib/route/neigh.c >> create mode 100644 libnetwork/libnl3/lib/route/neightbl.c >> create mode 100644 libnetwork/libnl3/lib/route/nexthop.c >> create mode 100644 libnetwork/libnl3/lib/route/pktloc.c >> create mode 100644 libnetwork/libnl3/lib/route/pktloc_grammar.l >> create mode 100644 libnetwork/libnl3/lib/route/pktloc_syntax.y >> create mode 100644 libnetwork/libnl3/lib/route/qdisc.c >> create mode 100644 libnetwork/libnl3/lib/route/qdisc/.dirstamp >> create mode 100644 libnetwork/libnl3/lib/route/qdisc/blackhole.c >> create mode 100644 libnetwork/libnl3/lib/route/qdisc/cbq.c >> create mode 100644 libnetwork/libnl3/lib/route/qdisc/dsmark.c >> create mode 100644 libnetwork/libnl3/lib/route/qdisc/fifo.c >> create mode 100644 libnetwork/libnl3/lib/route/qdisc/htb.c >> create mode 100644 libnetwork/libnl3/lib/route/qdisc/netem.c >> create mode 100644 libnetwork/libnl3/lib/route/qdisc/prio.c >> create mode 100644 libnetwork/libnl3/lib/route/qdisc/red.c >> create mode 100644 libnetwork/libnl3/lib/route/qdisc/sfq.c >> create mode 100644 libnetwork/libnl3/lib/route/qdisc/tbf.c >> create mode 100644 libnetwork/libnl3/lib/route/route.c >> create mode 100644 libnetwork/libnl3/lib/route/route_obj.c >> create mode 100644 libnetwork/libnl3/lib/route/route_utils.c >> create mode 100644 libnetwork/libnl3/lib/route/rtnl.c >> create mode 100644 libnetwork/libnl3/lib/route/rule.c >> create mode 100644 libnetwork/libnl3/lib/route/tc.c >> create mode 100644 libnetwork/libnl3/lib/socket.c >> create mode 100644 libnetwork/libnl3/lib/stamp-h1 >> create mode 100644 libnetwork/libnl3/lib/utils.c >> create mode 100644 libxkutil/network_model_helper.c >> create mode 100644 libxkutil/network_model_helper.h >> create mode 100644 schema/EthernetPort.mof >> create mode 100644 schema/EthernetPort.registration >> create mode 100644 schema/EthernetPortAllocationSettingData.mof >> create mode 100644 schema/EthernetPortAllocationSettingData.registration >> create mode 100644 schema/VirtualEthernetSwitchSystem.mof >> create mode 100644 schema/VirtualEthernetSwitchSystem.registration >> create mode 100644 schema/VirtualEthernetSwitchSystemSettingData.mof >> create mode 100644 >> schema/VirtualEthernetSwitchSystemSettingData.registration >> create mode 100644 src/Virt_EASD.c >> create mode 100644 src/Virt_EASD.h >> create mode 100644 src/Virt_EthernetPort.c >> create mode 100644 src/Virt_EthernetPort.h >> create mode 100644 src/Virt_VESSSD.c >> create mode 100644 src/Virt_VESSSD.h >> create mode 100644 src/Virt_VirtualEthernetSwitchSystem.c >> create mode 100644 src/Virt_VirtualEthernetSwitchSystem.h >> > > -- Best Regards Wayne Xia mail:xiawenc at linux.vnet.ibm.com tel:86-010-82450803 From eblima at linux.vnet.ibm.com Wed Jan 18 15:47:08 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Wed, 18 Jan 2012 13:47:08 -0200 Subject: [Libvirt-cim] [PATCH 2/4] Fix possible memory leaks In-Reply-To: References: <1326480802-6035-1-git-send-email-eblima@linux.vnet.ibm.com> <1326480802-6035-3-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F16E97C.8090904@linux.vnet.ibm.com> On 01/18/2012 02:54 AM, Sharad Mishra wrote: [snip] >> diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c >> index 96b4e96..7fff4d1 100644 >> --- a/libxkutil/xmlgen.c >> +++ b/libxkutil/xmlgen.c >> @@ -928,7 +928,6 @@ char *device_to_xml(struct virt_device *_dev) >> dominfo->dev_input = dev; >> break; >> default: >> - cleanup_virt_devices(&dev, 1); > > This change is causing FilterList -> 03_create.py to dump core. There are > few others that are segfaulting. > > -Sharad You're right, it will end up in a double-free. Thanks for the spot. Will send the patch with the correct fix once again. Best regards, Etrunko -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Wed Jan 18 16:06:08 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Wed, 18 Jan 2012 14:06:08 -0200 Subject: [Libvirt-cim] [PATCH v3 0/4] Fix errors raised by Coverity tool Message-ID: <1326902772-18178-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Yet another series of patches fixing errors revealed by Coverity tool. It would be nice if we had a similar setup so we could run the tool on a regular basis. I started playing with clang a while ago. It also provides a static analyser, but I could not complete the setup by then. https://bugzilla.redhat.com/show_bug.cgi?id=750418 Changes from v2: - Revert leak change for libxkutil/xmlgen.c in patch 2 which was causing a double-free crash and correctly fix the leak problem. Changes from v1: - Fix compilation error in Patch 1 Best regards, Etrunko -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com Eduardo Lima (Etrunko) (4): libxkutil: Fix possible NULL dereferences Fix possible memory leaks xml_parse_test: Fix invalid dereference Fix possible use of unitialized variables libxkutil/cs_util_instance.c | 5 +++++ libxkutil/device_parsing.c | 14 +++++++------- libxkutil/pool_parsing.c | 5 +++-- libxkutil/xml_parse_test.c | 3 +-- libxkutil/xmlgen.c | 8 +++++--- src/Virt_AppliedFilterList.c | 3 ++- src/Virt_Device.c | 20 ++++++++++++++++++++ src/Virt_DevicePool.c | 19 ++++++++++++++++++- src/Virt_SwitchService.c | 24 ++++++++++++++++++++---- src/Virt_VirtualSystemManagementService.c | 16 ++++++++-------- src/Virt_VirtualSystemSnapshotService.c | 2 +- 11 files changed, 90 insertions(+), 29 deletions(-) -- 1.7.7.5 From eblima at linux.vnet.ibm.com Wed Jan 18 16:06:12 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Wed, 18 Jan 2012 14:06:12 -0200 Subject: [Libvirt-cim] [PATCH 4/4] Fix possible use of unitialized variables In-Reply-To: <1326902772-18178-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326902772-18178-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1326902772-18178-5-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" As revealed by recent Coverity scan report provided by Red Hat: https://bugzilla.redhat.com/show_bug.cgi?id=750418 https://bugzilla.redhat.com/attachment.cgi?id=552325 Error: UNINIT: Virt_VirtualSystemManagementService.c:2798: var_decl: Declaring variable "s" without initializer. Virt_VirtualSystemManagementService.c:2901: uninit_use: Using uninitialized value "s": field "s".msg is uninitialized. Error: UNINIT: Virt_VirtualSystemSnapshotService.c:393: var_decl: Declaring variable "s" without initializer. Virt_VirtualSystemSnapshotService.c:398: uninit_use_in_call: Using uninitialized value "s.rc" when calling "new_context". Virt_VirtualSystemSnapshotService.c:378: read_parm_fld: Reading a parameter field. Signed-off-by: Eduardo Lima (Etrunko) --- src/Virt_VirtualSystemManagementService.c | 2 +- src/Virt_VirtualSystemSnapshotService.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c index 3a0b423..6f42c42 100644 --- a/src/Virt_VirtualSystemManagementService.c +++ b/src/Virt_VirtualSystemManagementService.c @@ -2732,7 +2732,7 @@ static CMPIStatus _update_resources_for(const CMPIContext *context, CMPIInstance *rasd, resmod_fn func) { - CMPIStatus s; + CMPIStatus s = {CMPI_RC_OK, NULL}; struct domain *dominfo = NULL; uint16_t type; char *xml = NULL; diff --git a/src/Virt_VirtualSystemSnapshotService.c b/src/Virt_VirtualSystemSnapshotService.c index 898fa57..aae628f 100644 --- a/src/Virt_VirtualSystemSnapshotService.c +++ b/src/Virt_VirtualSystemSnapshotService.c @@ -390,7 +390,7 @@ static CMPIStatus start_snapshot_job(const CMPIObjectPath *ref, CMPIArgs *argsout) { struct snap_context *ctx; - CMPIStatus s; + CMPIStatus s = {CMPI_RC_OK, NULL}; CMPIObjectPath *job; CMPIObjectPath *vssd; CMPIInstance *inst; -- 1.7.7.5 From eblima at linux.vnet.ibm.com Wed Jan 18 16:06:10 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Wed, 18 Jan 2012 14:06:10 -0200 Subject: [Libvirt-cim] [PATCH 2/4] Fix possible memory leaks In-Reply-To: <1326902772-18178-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326902772-18178-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1326902772-18178-3-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" As revealed by recent Coverity scan report provided by Red Hat: https://bugzilla.redhat.com/show_bug.cgi?id=750418 https://bugzilla.redhat.com/attachment.cgi?id=552325 Error: RESOURCE_LEAK: pool_parsing.c:140: alloc_fn: Calling allocation function "realloc". pool_parsing.c:140: var_assign: Assigning: "tmp" = storage returned from "realloc(dev_paths, 8UL * (ct + 1U))". pool_parsing.c:145: var_assign: Assigning: "dev_paths" = "tmp". pool_parsing.c:149: leaked_storage: Variable "tmp" going out of scope leaks the storage it points to. pool_parsing.c:169: leaked_storage: Variable "dev_paths" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: xmlgen.c:891: alloc_fn: Calling allocation function "virt_device_dup". device_parsing.c:873: alloc_fn: Storage is returned from allocation function "calloc". device_parsing.c:873: var_assign: Assigning: "dev" = "calloc(1UL, 152UL)". device_parsing.c:928: return_alloc: Returning allocated memory "dev". xmlgen.c:891: var_assign: Assigning: "dev" = storage returned from "virt_device_dup(_dev)". xmlgen.c:952: leaked_storage: Variable "dev" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: device_parsing.c:354: alloc_fn: Calling allocation function "calloc". device_parsing.c:354: var_assign: Assigning: "vsi_dev" = storage returned from "calloc(1UL, 56UL)". device_parsing.c:385: noescape: Variable "vsi_dev" is not freed or pointed-to in function "memcpy". device_parsing.c:386: leaked_storage: Variable "vsi_dev" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_DevicePool.c:1077: alloc_arg: Calling allocation function "get_diskpool_config" on "pools". Virt_DevicePool.c:161: alloc_arg: "get_disk_parent" allocates memory that is stored into "pools". Virt_DevicePool.c:74: alloc_fn: Storage is returned from allocation function "realloc". Virt_DevicePool.c:74: var_assign: Assigning: "pools" = "realloc(pools, (count + 1) * 24UL)". Virt_DevicePool.c:86: var_assign: Assigning: "*_pools" = "pools". Virt_DevicePool.c:163: var_assign: Assigning: "*_pools" = "pools". Virt_DevicePool.c:1080: leaked_storage: Variable "pools" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_DevicePool.c:404: alloc_arg: Calling allocation function "get_diskpool_config" on "pools". Virt_DevicePool.c:161: alloc_arg: "get_disk_parent" allocates memory that is stored into "pools". Virt_DevicePool.c:74: alloc_fn: Storage is returned from allocation function "realloc". Virt_DevicePool.c:74: var_assign: Assigning: "pools" = "realloc(pools, (count + 1) * 24UL)". Virt_DevicePool.c:86: var_assign: Assigning: "*_pools" = "pools". Virt_DevicePool.c:163: var_assign: Assigning: "*_pools" = "pools". Virt_DevicePool.c:406: leaked_storage: Variable "pools" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_VirtualSystemManagementService.c:415: alloc_fn: Calling allocation function "realloc". Virt_VirtualSystemManagementService.c:415: var_assign: Assigning: "tmp_str_arr" = storage returned from "realloc(domain->os_info.fv.bootlist, bl_size * 8UL)". Virt_VirtualSystemManagementService.c:432: leaked_storage: Variable "tmp_str_arr" going out of scope leaks the storage it points to. Virt_VirtualSystemManagementService.c:440: leaked_storage: Variable "tmp_str_arr" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_VirtualSystemManagementService.c:2834: alloc_fn: Calling allocation function "malloc". Virt_VirtualSystemManagementService.c:2834: var_assign: Assigning: "__retval" = storage returned from "malloc(__len)". Virt_VirtualSystemManagementService.c:2834: noescape: Variable "__retval" is not freed or pointed-to in function "memcpy". Virt_VirtualSystemManagementService.c:2834: overwrite_var: Overwriting "__retval" in call "__retval = (char *)memcpy(__retval, "ResourceAllocationSettingDataCreatedIndication", __len)" leaks the storage that "__retval" points to. Virt_VirtualSystemManagementService.c:2834: var_assign: Assigning: "__retval" = storage returned from "memcpy(__retval, "ResourceAllocationSettingDataCreatedIndication", __len)". Virt_VirtualSystemManagementService.c:2834: var_assign: Assigning: "indication" = "__retval". Virt_VirtualSystemManagementService.c:2901: leaked_storage: Variable "indication" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_VirtualSystemManagementService.c:2837: alloc_fn: Calling allocation function "malloc". Virt_VirtualSystemManagementService.c:2837: var_assign: Assigning: "__retval" = storage returned from "malloc(__len)". Virt_VirtualSystemManagementService.c:2837: noescape: Variable "__retval" is not freed or pointed-to in function "memcpy". Virt_VirtualSystemManagementService.c:2837: overwrite_var: Overwriting "__retval" in call "__retval = (char *)memcpy(__retval, "ResourceAllocationSettingDataDeletedIndication", __len)" leaks the storage that "__retval" points to. Virt_VirtualSystemManagementService.c:2837: var_assign: Assigning: "__retval" = storage returned from "memcpy(__retval, "ResourceAllocationSettingDataDeletedIndication", __len)". Virt_VirtualSystemManagementService.c:2837: var_assign: Assigning: "indication" = "__retval". Virt_VirtualSystemManagementService.c:2901: leaked_storage: Variable "indication" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_VirtualSystemManagementService.c:2840: alloc_fn: Calling allocation function "malloc". Virt_VirtualSystemManagementService.c:2840: var_assign: Assigning: "__retval" = storage returned from "malloc(__len)". Virt_VirtualSystemManagementService.c:2840: noescape: Variable "__retval" is not freed or pointed-to in function "memcpy". Virt_VirtualSystemManagementService.c:2840: overwrite_var: Overwriting "__retval" in call "__retval = (char *)memcpy(__retval, "ResourceAllocationSettingDataModifiedIndication", __len)" leaks the storage that "__retval" points to. Virt_VirtualSystemManagementService.c:2840: var_assign: Assigning: "__retval" = storage returned from "memcpy(__retval, "ResourceAllocationSettingDataModifiedIndication", __len)". Virt_VirtualSystemManagementService.c:2840: var_assign: Assigning: "indication" = "__retval". Virt_VirtualSystemManagementService.c:2901: leaked_storage: Variable "indication" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_AppliedFilterList.c:199: alloc_arg: Calling allocation function "get_domain_list" on "doms". cs_util_instance.c:52: alloc_fn: Storage is returned from allocation function "calloc". cs_util_instance.c:52: var_assign: Assigning: "list" = "calloc(n_names + n_ids, 8UL)". cs_util_instance.c:107: var_assign: Assigning: "*_list" = "list". Virt_AppliedFilterList.c:251: leaked_storage: Variable "doms" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: misc_util.c:275: alloc_arg: Calling allocation function "get_domain_list" on "list". cs_util_instance.c:52: alloc_fn: Storage is returned from allocation function "calloc". cs_util_instance.c:52: var_assign: Assigning: "list" = "calloc(n_names + n_ids, 8UL)". cs_util_instance.c:107: var_assign: Assigning: "*_list" = "list". misc_util.c:277: leaked_storage: Variable "list" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_SwitchService.c:108: alloc_fn: Calling allocation function "popen". Virt_SwitchService.c:108: var_assign: Assigning: "stream" = storage returned from "popen(func, "r")". Virt_SwitchService.c:118: noescape: Variable "stream" is not freed or pointed-to in function "fgets". Virt_SwitchService.c:131: leaked_storage: Variable "stream" going out of scope leaks the storage it points to. Virt_SwitchService.c:142: leaked_storage: Variable "stream" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_SwitchService.c:123: alloc_fn: Calling allocation function "realloc". Virt_SwitchService.c:123: var_assign: Assigning: "tmp_list" = storage returned from "realloc(arr, (i + 1) * 8UL)". Virt_SwitchService.c:134: var_assign: Assigning: "arr" = "tmp_list". Virt_SwitchService.c:142: leaked_storage: Variable "arr" going out of scope leaks the storage it points to. Virt_SwitchService.c:142: leaked_storage: Variable "tmp_list" going out of scope leaks the storage it points to. Error: RESOURCE_LEAK: Virt_SwitchService.c:236: alloc_fn: Calling allocation function "run_command". Virt_SwitchService.c:123: alloc_fn: Storage is returned from allocation function "realloc". Virt_SwitchService.c:123: var_assign: Assigning: "tmp_list" = "realloc(arr, (i + 1) * 8UL)". Virt_SwitchService.c:134: var_assign: Assigning: "arr" = "tmp_list". Virt_SwitchService.c:151: return_alloc: Returning allocated memory "arr". Virt_SwitchService.c:236: var_assign: Assigning: "if_list" = storage returned from "run_command("/sbin/ifconfig -a | /bin/grep eth | /bin/awk \'{print$1}\'", &count, &s)". /builddir/build/BUILD/libvirt-cim-0.6.0/src/Virt_SwitchService.c:269: leaked_storage: Variable "if_list" going out of scope leaks the storage it points to. Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/cs_util_instance.c | 5 +++++ libxkutil/device_parsing.c | 1 + libxkutil/pool_parsing.c | 5 +++-- libxkutil/xmlgen.c | 4 +++- src/Virt_AppliedFilterList.c | 3 ++- src/Virt_DevicePool.c | 5 ++++- src/Virt_SwitchService.c | 24 ++++++++++++++++++++---- src/Virt_VirtualSystemManagementService.c | 14 +++++++------- 8 files changed, 45 insertions(+), 16 deletions(-) diff --git a/libxkutil/cs_util_instance.c b/libxkutil/cs_util_instance.c index d21f0ff..a383147 100644 --- a/libxkutil/cs_util_instance.c +++ b/libxkutil/cs_util_instance.c @@ -104,6 +104,11 @@ int get_domain_list(virConnectPtr conn, virDomainPtr **_list) free(names); free(ids); + if (idx == 0) { + free(list); + list = NULL; + } + *_list = list; return idx; diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c index b0eccfc..a1e8d6c 100644 --- a/libxkutil/device_parsing.c +++ b/libxkutil/device_parsing.c @@ -382,6 +382,7 @@ static int parse_vsi_device(xmlNode *dnode, struct net_device *vdevs) } memcpy(&(vdevs->vsi), vsi_dev, sizeof(*vsi_dev)); + free(vsi_dev); return 1; err: diff --git a/libxkutil/pool_parsing.c b/libxkutil/pool_parsing.c index f73b0fd..e41fc09 100644 --- a/libxkutil/pool_parsing.c +++ b/libxkutil/pool_parsing.c @@ -163,10 +163,11 @@ static int parse_disk_source(xmlNode *node, struct disk_pool *pool) pool->device_paths_ct = ct; pool->device_paths = dev_paths; + return 1; err: - - return 1; + free(dev_paths); + return 0; } char *get_disk_pool_type(uint16_t type) diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index 96b4e96..9a2ada9 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -889,8 +889,10 @@ char *device_to_xml(struct virt_device *_dev) goto out; root = xmlNewNode(NULL, BAD_CAST "tmp"); - if (root == NULL) + if (root == NULL) { + cleanup_virt_devices(&dev, 1); goto out; + } switch (type) { case CIM_RES_TYPE_DISK: diff --git a/src/Virt_AppliedFilterList.c b/src/Virt_AppliedFilterList.c index 6567118..bc31c14 100644 --- a/src/Virt_AppliedFilterList.c +++ b/src/Virt_AppliedFilterList.c @@ -197,7 +197,7 @@ static CMPIStatus list_to_net( /* get domains */ dcount = get_domain_list(conn, &doms); - if (dcount < 0) { + if (dcount <= 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, "Failed to get domain list"); @@ -246,6 +246,7 @@ static CMPIStatus list_to_net( } out: + free(doms); virConnectClose(conn); return s; diff --git a/src/Virt_DevicePool.c b/src/Virt_DevicePool.c index ab0baa0..fe5573f 100644 --- a/src/Virt_DevicePool.c +++ b/src/Virt_DevicePool.c @@ -402,8 +402,10 @@ static char *_diskpool_member_of(virConnectPtr conn, char *pool = NULL; count = get_diskpool_config(conn, &pools); - if (count == 0) + if (count == 0) { + free(pools); return NULL; + } for (i = 0; i < count; i++) { if (_diskpool_is_member(conn, &pools[i], file)) { @@ -1091,6 +1093,7 @@ static CMPIStatus diskpool_instance(virConnectPtr conn, count = get_diskpool_config(conn, &pools); if ((id == NULL) && (count == 0)) { CU_DEBUG("No defined DiskPools"); + free(pools); return s; } diff --git a/src/Virt_SwitchService.c b/src/Virt_SwitchService.c index 0d57f54..7e59d38 100644 --- a/src/Virt_SwitchService.c +++ b/src/Virt_SwitchService.c @@ -128,20 +128,19 @@ static char **run_command(char *func, int *len, CMPIStatus *s) { cu_statusf(_BROKER, s, CMPI_RC_ERR_NOT_FOUND, "Failed to realloc"); - return NULL; + goto err; } arr = tmp_list; - string = calloc(len, sizeof(char)); + string = strndup(buff, len); if (string == NULL) { CU_DEBUG("Failed to allocate memory"); cu_statusf(_BROKER, s, CMPI_RC_ERR_NOT_FOUND, "Failed to calloc"); - return NULL; + goto err; } - strncpy(string, buff, len); arr[i] = string; i++; } @@ -149,6 +148,19 @@ static char **run_command(char *func, int *len, CMPIStatus *s) { pclose(stream); *len = i; return arr; + + err: + /* undo everything */ + if (i > 0) { + int count; + for (count = 0; count < i; count++) + free(arr[count]); + } + + free(arr); + pclose(stream); + return NULL; + } static CMPIStatus set_inst_properties(const CMPIBroker *broker, @@ -262,6 +274,10 @@ static CMPIStatus get_switchservice(const CMPIObjectPath *reference, CMSetProperty(inst, "IsVSISupported", (CMPIValue *)&vsi, CMPI_boolean); s.rc = CMPI_RC_OK; + for (i = 0; i < count; i++) + free(if_list[i]); + + free(if_list); out: virConnectClose(conn); *_inst = inst; diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c index f8c5f24..3a0b423 100644 --- a/src/Virt_VirtualSystemManagementService.c +++ b/src/Virt_VirtualSystemManagementService.c @@ -429,6 +429,7 @@ static int bootord_vssd_to_domain(CMPIInstance *inst, if (CMIsNullValue(boot_elem)) { CU_DEBUG("Null BootDevice"); + free(tmp_str_arr); return 0; } @@ -437,6 +438,7 @@ static int bootord_vssd_to_domain(CMPIInstance *inst, if (str == NULL) { CU_DEBUG("Could not extract char pointer from " "CMPIArray"); + free(tmp_str_arr); return 0; } @@ -2766,13 +2768,11 @@ static CMPIStatus _update_resources_for(const CMPIContext *context, } if (func == &resource_add) { - indication = strdup(RASD_IND_CREATED); - } - else if (func == &resource_del) { - indication = strdup(RASD_IND_DELETED); - } - else { - indication = strdup(RASD_IND_MODIFIED); + indication = RASD_IND_CREATED; + } else if (func == &resource_del) { + indication = RASD_IND_DELETED; + } else { + indication = RASD_IND_MODIFIED; char *dummy_name = NULL; if (asprintf(&dummy_name, "%s/%s",dominfo->name, devid) == -1) { -- 1.7.7.5 From eblima at linux.vnet.ibm.com Wed Jan 18 16:06:11 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Wed, 18 Jan 2012 14:06:11 -0200 Subject: [Libvirt-cim] [PATCH 3/4] xml_parse_test: Fix invalid dereference In-Reply-To: <1326902772-18178-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326902772-18178-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1326902772-18178-4-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" As revealed by recent Coverity scan report provided by Red Hat: https://bugzilla.redhat.com/show_bug.cgi?id=750418 https://bugzilla.redhat.com/attachment.cgi?id=552325 Error: USE_AFTER_FREE: xml_parse_test.c:239: freed_arg: "free" frees "xml". xml_parse_test.c:242: pass_freed_arg: Passing freed pointer "xml" as an argument to function "printf". Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/xml_parse_test.c | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/libxkutil/xml_parse_test.c b/libxkutil/xml_parse_test.c index 16ceefb..384593d 100644 --- a/libxkutil/xml_parse_test.c +++ b/libxkutil/xml_parse_test.c @@ -236,11 +236,10 @@ static int dominfo_from_file(const char *fname, struct domain **d) ret = get_dominfo_from_xml(xml, d); + printf("XML:\n%s", xml); free(xml); fclose(file); - printf("XML:\n%s", xml); - return ret; } -- 1.7.7.5 From eblima at linux.vnet.ibm.com Wed Jan 18 16:06:09 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Wed, 18 Jan 2012 14:06:09 -0200 Subject: [Libvirt-cim] [PATCH 1/4] libxkutil: Fix possible NULL dereferences In-Reply-To: <1326902772-18178-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326902772-18178-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1326902772-18178-2-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" As revealed by recent Coverity scan report provided by Red Hat: https://bugzilla.redhat.com/show_bug.cgi?id=750418 https://bugzilla.redhat.com/attachment.cgi?id=552325 Error: FORWARD_NULL: xmlgen.c:100: var_compare_op: Comparing "dev->device" to null implies that "dev->device" might be null. xmlgen.c:115: var_deref_model: Passing null variable "(char *)dev->device" to function "__coverity_strcmp", which dereferences it. Error: FORWARD_NULL: device_parsing.c:615: var_compare_op: Comparing "gdev->type" to null implies that "gdev->type" might be null. device_parsing.c:677: var_deref_model: Passing null variable "gdev->type" to function "cleanup_graphics_device", which dereferences it. device_parsing.c:126: deref_parm_in_call: Function "strcasecmp" dereferences parameter "dev->type". (The dereference is assumed on the basis of the 'nonnull' parameter attribute.) Error: NULL_RETURNS: Virt_DevicePool.c:805: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_DevicePool.c:805: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_DevicePool.c:810: dereference: Dereferencing a pointer that might be null "inst" when calling "mempool_set_total". Virt_DevicePool.c:686: deref_parm: Directly dereferencing parameter "inst". Error: NULL_RETURNS: Virt_DevicePool.c:837: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_DevicePool.c:837: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_DevicePool.c:842: dereference: Dereferencing a pointer that might be null "inst" when calling "procpool_set_total". Virt_DevicePool.c:743: deref_parm: Directly dereferencing parameter "inst". Error: NULL_RETURNS: Virt_Device.c:219: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_Device.c:219: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_Device.c:224: dereference: Dereferencing a pointer that might be null "inst" when calling "graphics_set_attr". Virt_Device.c:202: deref_parm: Directly dereferencing parameter "instance". Error: NULL_RETURNS: Virt_Device.c:133: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_Device.c:133: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_Device.c:138: dereference: Dereferencing a pointer that might be null "inst" when calling "disk_set_name". Virt_Device.c:117: deref_parm: Directly dereferencing parameter "instance". Error: NULL_RETURNS: Virt_Device.c:175: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_Device.c:175: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_Device.c:180: dereference: Dereferencing a pointer that might be null "inst" when calling "mem_set_size". Virt_Device.c:156: deref_parm: Directly dereferencing parameter "instance". Error: NULL_RETURNS: Virt_Device.c:100: returned_null: Function "get_typed_instance" returns null (checked 37 out of 44 times). misc_util.c:348: null_assign: Assigning: "inst" = NULL. misc_util.c:369: return_null_var: Returning "inst", which is null. Virt_Device.c:100: var_assigned: Assigning: "inst" = null return value from "get_typed_instance". Virt_Device.c:105: dereference: Dereferencing a pointer that might be null "inst" when calling "net_set_type". Virt_Device.c:61: deref_parm: Directly dereferencing parameter "instance". Signed-off-byr Eduardo Lima (Etrunko) --- libxkutil/device_parsing.c | 13 ++++++------- libxkutil/xmlgen.c | 4 ++-- src/Virt_Device.c | 20 ++++++++++++++++++++ src/Virt_DevicePool.c | 14 ++++++++++++++ 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c index 7eaa63e..b0eccfc 100644 --- a/libxkutil/device_parsing.c +++ b/libxkutil/device_parsing.c @@ -120,15 +120,14 @@ static void cleanup_sdl_device(struct graphics_device *dev) static void cleanup_graphics_device(struct graphics_device *dev) { - if (dev == NULL) + if (dev == NULL || dev->type == NULL) return; - if (STREQC(dev->type, "sdl")) { - cleanup_sdl_device(dev); - } - else { - cleanup_vnc_device(dev); - } + if (STREQC(dev->type, "sdl")) + cleanup_sdl_device(dev); + else + cleanup_vnc_device(dev); + free(dev->type); } diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index d73ffd0..96b4e96 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -112,8 +112,8 @@ static const char *disk_file_xml(xmlNodePtr root, struct disk_device *dev) xmlNewProp(tmp, BAD_CAST "cache", BAD_CAST dev->cache); } - if ((XSTREQ(dev->device, "cdrom")) && - (XSTREQ(dev->source, ""))) { + if (dev->device != NULL && XSTREQ(dev->device, "cdrom") && + XSTREQ(dev->source, "")) { /* This is the situation that user defined a cdrom device without disk in it, so skip generating a line saying "source", for that xml defination for libvirt should not have this defined in this diff --git a/src/Virt_Device.c b/src/Virt_Device.c index fd11370..abe3d6f 100644 --- a/src/Virt_Device.c +++ b/src/Virt_Device.c @@ -102,6 +102,11 @@ static CMPIInstance *net_instance(const CMPIBroker *broker, "NetworkPort", ns); + if (inst == NULL) { + CU_DEBUG("Failed to get instance for NetworkPort"); + return NULL; + } + if (!net_set_type(inst, dev)) return NULL; @@ -135,6 +140,11 @@ static CMPIInstance *disk_instance(const CMPIBroker *broker, "LogicalDisk", ns); + if (inst == NULL) { + CU_DEBUG("Failed to get instance for LogicalDisk"); + return NULL; + } + if (!disk_set_name(inst, dev)) return NULL; @@ -177,6 +187,11 @@ static CMPIInstance *mem_instance(const CMPIBroker *broker, "Memory", ns); + if (inst == NULL) { + CU_DEBUG("Failed to get instance for Memory"); + return NULL; + } + if (!mem_set_size(inst, dev)) return NULL; @@ -221,6 +236,11 @@ static CMPIInstance *graphics_instance(const CMPIBroker *broker, "DisplayController", ns); + if (inst == NULL) { + CU_DEBUG("Failed to get instance for DisplayController"); + return NULL; + } + if (!graphics_set_attr(inst, dev)) return NULL; diff --git a/src/Virt_DevicePool.c b/src/Virt_DevicePool.c index a41a378..ab0baa0 100644 --- a/src/Virt_DevicePool.c +++ b/src/Virt_DevicePool.c @@ -807,6 +807,13 @@ static CMPIStatus mempool_instance(virConnectPtr conn, "MemoryPool", ns); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Failed to get instance for MemoryPool"); + return s; + } + mempool_set_total(inst, conn); mempool_set_consumed(inst, conn); @@ -839,6 +846,13 @@ static CMPIStatus procpool_instance(virConnectPtr conn, "ProcessorPool", ns); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Failed to get instance for ProcessorPool"); + return s; + } + procpool_set_total(inst, conn); set_params(inst, CIM_RES_TYPE_PROC, id, "Processors", NULL, true); -- 1.7.7.5 From cvincent at linux.vnet.ibm.com Wed Jan 18 16:20:05 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Wed, 18 Jan 2012 11:20:05 -0500 Subject: [Libvirt-cim] [PATCH] autoconfiscate.sh: Use proper command for revision count In-Reply-To: <4F15AFCC.1020802@linux.vnet.ibm.com> References: <1326819497-30936-1-git-send-email-eblima@linux.vnet.ibm.com> <4F15AAA1.9000501@linux.vnet.ibm.com> <4F15AFCC.1020802@linux.vnet.ibm.com> Message-ID: <4F16F135.40603@linux.vnet.ibm.com> On 01/17/2012 12:28 PM, Eduardo Lima (Etrunko) wrote: > git rev-list HEAD | wc -l This works as expected. I see '1179' in my current dev branch. FWIW: I'm using git-1.7.1-2.el6_0.1.x86_64 -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From eblima at linux.vnet.ibm.com Wed Jan 18 16:28:03 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Wed, 18 Jan 2012 14:28:03 -0200 Subject: [Libvirt-cim] [PATCH] autoconfiscate.sh: Use proper command for revision count In-Reply-To: <4F16F135.40603@linux.vnet.ibm.com> References: <1326819497-30936-1-git-send-email-eblima@linux.vnet.ibm.com> <4F15AAA1.9000501@linux.vnet.ibm.com> <4F15AFCC.1020802@linux.vnet.ibm.com> <4F16F135.40603@linux.vnet.ibm.com> Message-ID: <4F16F313.90303@linux.vnet.ibm.com> On 01/18/2012 02:20 PM, Chip Vincent wrote: > On 01/17/2012 12:28 PM, Eduardo Lima (Etrunko) wrote: >> git rev-list HEAD | wc -l > This works as expected. I see '1179' in my current dev branch. > > FWIW: I'm using git-1.7.1-2.el6_0.1.x86_64 > Ok, mine is version 1.7.7.5, which ships in fedora 16. Resending the patch right now. -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Wed Jan 18 16:32:09 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Wed, 18 Jan 2012 14:32:09 -0200 Subject: [Libvirt-cim] [PATCH v2] autoconfiscate.sh: Use proper command for revision count Message-ID: <1326904329-7730-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- autoconfiscate.sh | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/autoconfiscate.sh b/autoconfiscate.sh index 8ea8a30..6bdd90a 100755 --- a/autoconfiscate.sh +++ b/autoconfiscate.sh @@ -19,7 +19,7 @@ autoconf --force && if test -x $(which git); then git rev-parse --short HEAD > .changeset - git log | grep "^commit" | wc -l > .revision + git rev-list HEAD | wc -l > .revision else echo "Unknown" > .changeset echo "0" > .revision -- 1.7.7.5 From eblima at linux.vnet.ibm.com Wed Jan 18 16:35:48 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Wed, 18 Jan 2012 14:35:48 -0200 Subject: [Libvirt-cim] [PATCH v2] [TEST] Update revision and changeset info Message-ID: <1326904548-7892-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" We are now using git (yay!!). Port the commands from mercurial to the git equivalents. Signed-off-by: Eduardo Lima (Etrunko) --- suites/libvirt-cim/lib/XenKvmLib/reporting.py | 6 ++---- 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/suites/libvirt-cim/lib/XenKvmLib/reporting.py b/suites/libvirt-cim/lib/XenKvmLib/reporting.py index b6df36e..d24f41b 100644 --- a/suites/libvirt-cim/lib/XenKvmLib/reporting.py +++ b/suites/libvirt-cim/lib/XenKvmLib/reporting.py @@ -33,10 +33,8 @@ def get_cmd_val(cmd, ip): return out def get_cimtest_version(): - revision = commands.getoutput("hg parents --template \ - \"{rev}\" 2>/dev/null") - changeset = commands.getoutput("hg parents --template \ - \"{node|short}\" 2>/dev/null") + revision = commands.getoutput("git rev-list HEAD | wc -l 2>/dev/null") + changeset = commands.getoutput("git rev-parse --short HEAD 2>/dev/null") return revision, changeset def get_libvirt_ver(ip): -- 1.7.7.5 From cvincent at linux.vnet.ibm.com Wed Jan 18 18:29:40 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Wed, 18 Jan 2012 13:29:40 -0500 Subject: [Libvirt-cim] [PATCH v2] autoconfiscate.sh: Use proper command for revision count In-Reply-To: <1326904329-7730-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326904329-7730-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F170F94.2030809@linux.vnet.ibm.com> +1 $ cat .revision 1180 On 01/18/2012 11:32 AM, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > Signed-off-by: Eduardo Lima (Etrunko) > --- > autoconfiscate.sh | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/autoconfiscate.sh b/autoconfiscate.sh > index 8ea8a30..6bdd90a 100755 > --- a/autoconfiscate.sh > +++ b/autoconfiscate.sh > @@ -19,7 +19,7 @@ autoconf --force&& > > if test -x $(which git); then > git rev-parse --short HEAD> .changeset > - git log | grep "^commit" | wc -l> .revision > + git rev-list HEAD | wc -l> .revision > else > echo "Unknown"> .changeset > echo "0"> .revision -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From cvincent at linux.vnet.ibm.com Wed Jan 18 18:45:20 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Wed, 18 Jan 2012 13:45:20 -0500 Subject: [Libvirt-cim] [PATCH v2] [TEST] Update revision and changeset info In-Reply-To: <1326904548-7892-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326904548-7892-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F171340.2070908@linux.vnet.ibm.com> +1 Cimtest revision: 890 Cimtest changeset: d5deafb On 01/18/2012 11:35 AM, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > We are now using git (yay!!). Port the commands from mercurial to the git > equivalents. > > Signed-off-by: Eduardo Lima (Etrunko) > --- > suites/libvirt-cim/lib/XenKvmLib/reporting.py | 6 ++---- > 1 files changed, 2 insertions(+), 4 deletions(-) > > diff --git a/suites/libvirt-cim/lib/XenKvmLib/reporting.py b/suites/libvirt-cim/lib/XenKvmLib/reporting.py > index b6df36e..d24f41b 100644 > --- a/suites/libvirt-cim/lib/XenKvmLib/reporting.py > +++ b/suites/libvirt-cim/lib/XenKvmLib/reporting.py > @@ -33,10 +33,8 @@ def get_cmd_val(cmd, ip): > return out > > def get_cimtest_version(): > - revision = commands.getoutput("hg parents --template \ > - \"{rev}\" 2>/dev/null") > - changeset = commands.getoutput("hg parents --template \ > - \"{node|short}\" 2>/dev/null") > + revision = commands.getoutput("git rev-list HEAD | wc -l 2>/dev/null") > + changeset = commands.getoutput("git rev-parse --short HEAD 2>/dev/null") > return revision, changeset > > def get_libvirt_ver(ip): -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From snmishra at us.ibm.com Wed Jan 18 20:47:22 2012 From: snmishra at us.ibm.com (Sharad Mishra) Date: Wed, 18 Jan 2012 12:47:22 -0800 Subject: [Libvirt-cim] [PATCH 2/4] Fix possible memory leaks In-Reply-To: <1326902772-18178-3-git-send-email-eblima@linux.vnet.ibm.com> References: <1326902772-18178-1-git-send-email-eblima@linux.vnet.ibm.com> <1326902772-18178-3-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: +1 Sharad Mishra Open Virtualization Linux Technology Center IBM libvirt-cim-bounces at redhat.com wrote on 01/18/2012 08:06:10 AM: > "Eduardo Lima (Etrunko)" > Sent by: libvirt-cim-bounces at redhat.com > > 01/18/2012 08:06 AM > > Please respond to > List for discussion and development of libvirt CIM > > To > > libvirt-cim at redhat.com > > cc > > "Eduardo Lima \(Etrunko\)" > > Subject > > [Libvirt-cim] [PATCH 2/4] Fix possible memory leaks > > From: "Eduardo Lima (Etrunko)" > > As revealed by recent Coverity scan report provided by Red Hat: > https://bugzilla.redhat.com/show_bug.cgi?id=750418 > https://bugzilla.redhat.com/attachment.cgi?id=552325 > > Error: RESOURCE_LEAK: > pool_parsing.c:140: alloc_fn: Calling allocation function "realloc". > pool_parsing.c:140: var_assign: Assigning: "tmp" = storage returned > from "realloc(dev_paths, 8UL * (ct + 1U))". > pool_parsing.c:145: var_assign: Assigning: "dev_paths" = "tmp". > pool_parsing.c:149: leaked_storage: Variable "tmp" going out of > scope leaks the storage it points to. > pool_parsing.c:169: leaked_storage: Variable "dev_paths" going out > of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > xmlgen.c:891: alloc_fn: Calling allocation function "virt_device_dup". > device_parsing.c:873: alloc_fn: Storage is returned from allocation > function "calloc". > device_parsing.c:873: var_assign: Assigning: "dev" = "calloc(1UL, 152UL)". > device_parsing.c:928: return_alloc: Returning allocated memory "dev". > xmlgen.c:891: var_assign: Assigning: "dev" = storage returned from > "virt_device_dup(_dev)". > xmlgen.c:952: leaked_storage: Variable "dev" going out of scope > leaks the storage it points to. > > Error: RESOURCE_LEAK: > device_parsing.c:354: alloc_fn: Calling allocation function "calloc". > device_parsing.c:354: var_assign: Assigning: "vsi_dev" = storage > returned from "calloc(1UL, 56UL)". > device_parsing.c:385: noescape: Variable "vsi_dev" is not freed or > pointed-to in function "memcpy". > device_parsing.c:386: leaked_storage: Variable "vsi_dev" going out > of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_DevicePool.c:1077: alloc_arg: Calling allocation function > "get_diskpool_config" on "pools". > Virt_DevicePool.c:161: alloc_arg: "get_disk_parent" allocates memory > that is stored into "pools". > Virt_DevicePool.c:74: alloc_fn: Storage is returned from allocation > function "realloc". > Virt_DevicePool.c:74: var_assign: Assigning: "pools" = "realloc > (pools, (count + 1) * 24UL)". > Virt_DevicePool.c:86: var_assign: Assigning: "*_pools" = "pools". > Virt_DevicePool.c:163: var_assign: Assigning: "*_pools" = "pools". > Virt_DevicePool.c:1080: leaked_storage: Variable "pools" going out > of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_DevicePool.c:404: alloc_arg: Calling allocation function > "get_diskpool_config" on "pools". > Virt_DevicePool.c:161: alloc_arg: "get_disk_parent" allocates memory > that is stored into "pools". > Virt_DevicePool.c:74: alloc_fn: Storage is returned from allocation > function "realloc". > Virt_DevicePool.c:74: var_assign: Assigning: "pools" = "realloc > (pools, (count + 1) * 24UL)". > Virt_DevicePool.c:86: var_assign: Assigning: "*_pools" = "pools". > Virt_DevicePool.c:163: var_assign: Assigning: "*_pools" = "pools". > Virt_DevicePool.c:406: leaked_storage: Variable "pools" going out of > scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_VirtualSystemManagementService.c:415: alloc_fn: Calling > allocation function "realloc". > Virt_VirtualSystemManagementService.c:415: var_assign: Assigning: > "tmp_str_arr" = storage returned from "realloc > (domain->os_info.fv.bootlist, bl_size * 8UL)". > Virt_VirtualSystemManagementService.c:432: leaked_storage: Variable > "tmp_str_arr" going out of scope leaks the storage it points to. > Virt_VirtualSystemManagementService.c:440: leaked_storage: Variable > "tmp_str_arr" going out of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_VirtualSystemManagementService.c:2834: alloc_fn: Calling > allocation function "malloc". > Virt_VirtualSystemManagementService.c:2834: var_assign: Assigning: > "__retval" = storage returned from "malloc(__len)". > Virt_VirtualSystemManagementService.c:2834: noescape: Variable > "__retval" is not freed or pointed-to in function "memcpy". > Virt_VirtualSystemManagementService.c:2834: overwrite_var: > Overwriting "__retval" in call "__retval = (char *)memcpy(__retval, > "ResourceAllocationSettingDataCreatedIndication", __len)" leaks the > storage that "__retval" points to. > Virt_VirtualSystemManagementService.c:2834: var_assign: Assigning: > "__retval" = storage returned from "memcpy(__retval, > "ResourceAllocationSettingDataCreatedIndication", __len)". > Virt_VirtualSystemManagementService.c:2834: var_assign: Assigning: > "indication" = "__retval". > Virt_VirtualSystemManagementService.c:2901: leaked_storage: Variable > "indication" going out of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_VirtualSystemManagementService.c:2837: alloc_fn: Calling > allocation function "malloc". > Virt_VirtualSystemManagementService.c:2837: var_assign: Assigning: > "__retval" = storage returned from "malloc(__len)". > Virt_VirtualSystemManagementService.c:2837: noescape: Variable > "__retval" is not freed or pointed-to in function "memcpy". > Virt_VirtualSystemManagementService.c:2837: overwrite_var: > Overwriting "__retval" in call "__retval = (char *)memcpy(__retval, > "ResourceAllocationSettingDataDeletedIndication", __len)" leaks the > storage that "__retval" points to. > Virt_VirtualSystemManagementService.c:2837: var_assign: Assigning: > "__retval" = storage returned from "memcpy(__retval, > "ResourceAllocationSettingDataDeletedIndication", __len)". > Virt_VirtualSystemManagementService.c:2837: var_assign: Assigning: > "indication" = "__retval". > Virt_VirtualSystemManagementService.c:2901: leaked_storage: Variable > "indication" going out of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_VirtualSystemManagementService.c:2840: alloc_fn: Calling > allocation function "malloc". > Virt_VirtualSystemManagementService.c:2840: var_assign: Assigning: > "__retval" = storage returned from "malloc(__len)". > Virt_VirtualSystemManagementService.c:2840: noescape: Variable > "__retval" is not freed or pointed-to in function "memcpy". > Virt_VirtualSystemManagementService.c:2840: overwrite_var: > Overwriting "__retval" in call "__retval = (char *)memcpy(__retval, > "ResourceAllocationSettingDataModifiedIndication", __len)" leaks the > storage that "__retval" points to. > Virt_VirtualSystemManagementService.c:2840: var_assign: Assigning: > "__retval" = storage returned from "memcpy(__retval, > "ResourceAllocationSettingDataModifiedIndication", __len)". > Virt_VirtualSystemManagementService.c:2840: var_assign: Assigning: > "indication" = "__retval". > Virt_VirtualSystemManagementService.c:2901: leaked_storage: Variable > "indication" going out of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_AppliedFilterList.c:199: alloc_arg: Calling allocation function > "get_domain_list" on "doms". > cs_util_instance.c:52: alloc_fn: Storage is returned from allocation > function "calloc". > cs_util_instance.c:52: var_assign: Assigning: "list" = "calloc > (n_names + n_ids, 8UL)". > cs_util_instance.c:107: var_assign: Assigning: "*_list" = "list". > Virt_AppliedFilterList.c:251: leaked_storage: Variable "doms" going > out of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > misc_util.c:275: alloc_arg: Calling allocation function > "get_domain_list" on "list". > cs_util_instance.c:52: alloc_fn: Storage is returned from allocation > function "calloc". > cs_util_instance.c:52: var_assign: Assigning: "list" = "calloc > (n_names + n_ids, 8UL)". > cs_util_instance.c:107: var_assign: Assigning: "*_list" = "list". > misc_util.c:277: leaked_storage: Variable "list" going out of scope > leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_SwitchService.c:108: alloc_fn: Calling allocation function "popen". > Virt_SwitchService.c:108: var_assign: Assigning: "stream" = storage > returned from "popen(func, "r")". > Virt_SwitchService.c:118: noescape: Variable "stream" is not freed > or pointed-to in function "fgets". > Virt_SwitchService.c:131: leaked_storage: Variable "stream" going > out of scope leaks the storage it points to. > Virt_SwitchService.c:142: leaked_storage: Variable "stream" going > out of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_SwitchService.c:123: alloc_fn: Calling allocation function "realloc". > Virt_SwitchService.c:123: var_assign: Assigning: "tmp_list" = > storage returned from "realloc(arr, (i + 1) * 8UL)". > Virt_SwitchService.c:134: var_assign: Assigning: "arr" = "tmp_list". > Virt_SwitchService.c:142: leaked_storage: Variable "arr" going out > of scope leaks the storage it points to. > Virt_SwitchService.c:142: leaked_storage: Variable "tmp_list" going > out of scope leaks the storage it points to. > > Error: RESOURCE_LEAK: > Virt_SwitchService.c:236: alloc_fn: Calling allocation function "run_command". > Virt_SwitchService.c:123: alloc_fn: Storage is returned from > allocation function "realloc". > Virt_SwitchService.c:123: var_assign: Assigning: "tmp_list" = > "realloc(arr, (i + 1) * 8UL)". > Virt_SwitchService.c:134: var_assign: Assigning: "arr" = "tmp_list". > Virt_SwitchService.c:151: return_alloc: Returning allocated memory "arr". > Virt_SwitchService.c:236: var_assign: Assigning: "if_list" = > storage returned from "run_command("/sbin/ifconfig -a | /bin/grep > eth | /bin/awk \'{print$1}\'", &count, &s)". > /builddir/build/BUILD/libvirt-cim-0.6.0/src/Virt_SwitchService.c: > 269: leaked_storage: Variable "if_list" going out of scope leaks the > storage it points to. > > Signed-off-by: Eduardo Lima (Etrunko) > --- > libxkutil/cs_util_instance.c | 5 +++++ > libxkutil/device_parsing.c | 1 + > libxkutil/pool_parsing.c | 5 +++-- > libxkutil/xmlgen.c | 4 +++- > src/Virt_AppliedFilterList.c | 3 ++- > src/Virt_DevicePool.c | 5 ++++- > src/Virt_SwitchService.c | 24 +++++++++++++++++++ +---- > src/Virt_VirtualSystemManagementService.c | 14 +++++++------- > 8 files changed, 45 insertions(+), 16 deletions(-) > > diff --git a/libxkutil/cs_util_instance.c b/libxkutil/cs_util_instance.c > index d21f0ff..a383147 100644 > --- a/libxkutil/cs_util_instance.c > +++ b/libxkutil/cs_util_instance.c > @@ -104,6 +104,11 @@ int get_domain_list(virConnectPtr conn, > virDomainPtr **_list) > free(names); > free(ids); > > + if (idx == 0) { > + free(list); > + list = NULL; > + } > + > *_list = list; > > return idx; > diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c > index b0eccfc..a1e8d6c 100644 > --- a/libxkutil/device_parsing.c > +++ b/libxkutil/device_parsing.c > @@ -382,6 +382,7 @@ static int parse_vsi_device(xmlNode *dnode, > struct net_device *vdevs) > } > > memcpy(&(vdevs->vsi), vsi_dev, sizeof(*vsi_dev)); > + free(vsi_dev); > return 1; > > err: > diff --git a/libxkutil/pool_parsing.c b/libxkutil/pool_parsing.c > index f73b0fd..e41fc09 100644 > --- a/libxkutil/pool_parsing.c > +++ b/libxkutil/pool_parsing.c > @@ -163,10 +163,11 @@ static int parse_disk_source(xmlNode *node, > struct disk_pool *pool) > > pool->device_paths_ct = ct; > pool->device_paths = dev_paths; > + return 1; > > err: > - > - return 1; > + free(dev_paths); > + return 0; > } > > char *get_disk_pool_type(uint16_t type) > diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c > index 96b4e96..9a2ada9 100644 > --- a/libxkutil/xmlgen.c > +++ b/libxkutil/xmlgen.c > @@ -889,8 +889,10 @@ char *device_to_xml(struct virt_device *_dev) > goto out; > > root = xmlNewNode(NULL, BAD_CAST "tmp"); > - if (root == NULL) > + if (root == NULL) { > + cleanup_virt_devices(&dev, 1); > goto out; > + } > > switch (type) { > case CIM_RES_TYPE_DISK: > diff --git a/src/Virt_AppliedFilterList.c b/src/Virt_AppliedFilterList.c > index 6567118..bc31c14 100644 > --- a/src/Virt_AppliedFilterList.c > +++ b/src/Virt_AppliedFilterList.c > @@ -197,7 +197,7 @@ static CMPIStatus list_to_net( > > /* get domains */ > dcount = get_domain_list(conn, &doms); > - if (dcount < 0) { > + if (dcount <= 0) { > cu_statusf(_BROKER, &s, > CMPI_RC_ERR_FAILED, > "Failed to get domain list"); > @@ -246,6 +246,7 @@ static CMPIStatus list_to_net( > } > > out: > + free(doms); > virConnectClose(conn); > > return s; > diff --git a/src/Virt_DevicePool.c b/src/Virt_DevicePool.c > index ab0baa0..fe5573f 100644 > --- a/src/Virt_DevicePool.c > +++ b/src/Virt_DevicePool.c > @@ -402,8 +402,10 @@ static char *_diskpool_member_of(virConnectPtr conn, > char *pool = NULL; > > count = get_diskpool_config(conn, &pools); > - if (count == 0) > + if (count == 0) { > + free(pools); > return NULL; > + } > > for (i = 0; i < count; i++) { > if (_diskpool_is_member(conn, &pools[i], file)) { > @@ -1091,6 +1093,7 @@ static CMPIStatus diskpool_instance(virConnectPtr conn, > count = get_diskpool_config(conn, &pools); > if ((id == NULL) && (count == 0)) { > CU_DEBUG("No defined DiskPools"); > + free(pools); > return s; > } > > diff --git a/src/Virt_SwitchService.c b/src/Virt_SwitchService.c > index 0d57f54..7e59d38 100644 > --- a/src/Virt_SwitchService.c > +++ b/src/Virt_SwitchService.c > @@ -128,20 +128,19 @@ static char **run_command(char *func, int > *len, CMPIStatus *s) { > cu_statusf(_BROKER, s, > CMPI_RC_ERR_NOT_FOUND, > "Failed to realloc"); > - return NULL; > + goto err; > } > > arr = tmp_list; > > - string = calloc(len, sizeof(char)); > + string = strndup(buff, len); > if (string == NULL) { > CU_DEBUG("Failed to allocate memory"); > cu_statusf(_BROKER, s, > CMPI_RC_ERR_NOT_FOUND, > "Failed to calloc"); > - return NULL; > + goto err; > } > - strncpy(string, buff, len); > arr[i] = string; > i++; > } > @@ -149,6 +148,19 @@ static char **run_command(char *func, int *len, > CMPIStatus *s) { > pclose(stream); > *len = i; > return arr; > + > + err: > + /* undo everything */ > + if (i > 0) { > + int count; > + for (count = 0; count < i; count++) > + free(arr[count]); > + } > + > + free(arr); > + pclose(stream); > + return NULL; > + > } > > static CMPIStatus set_inst_properties(const CMPIBroker *broker, > @@ -262,6 +274,10 @@ static CMPIStatus get_switchservice(const > CMPIObjectPath *reference, > CMSetProperty(inst, "IsVSISupported", (CMPIValue *)&vsi, > CMPI_boolean); > s.rc = CMPI_RC_OK; > > + for (i = 0; i < count; i++) > + free(if_list[i]); > + > + free(if_list); > out: > virConnectClose(conn); > *_inst = inst; > diff --git a/src/Virt_VirtualSystemManagementService.c b/src/ > Virt_VirtualSystemManagementService.c > index f8c5f24..3a0b423 100644 > --- a/src/Virt_VirtualSystemManagementService.c > +++ b/src/Virt_VirtualSystemManagementService.c > @@ -429,6 +429,7 @@ static int bootord_vssd_to_domain(CMPIInstance *inst, > > if (CMIsNullValue(boot_elem)) { > CU_DEBUG("Null BootDevice"); > + free(tmp_str_arr); > return 0; > } > > @@ -437,6 +438,7 @@ static int bootord_vssd_to_domain(CMPIInstance *inst, > if (str == NULL) { > CU_DEBUG("Could not extract char pointer from " > "CMPIArray"); > + free(tmp_str_arr); > return 0; > } > > @@ -2766,13 +2768,11 @@ static CMPIStatus _update_resources_for > (const CMPIContext *context, > } > > if (func == &resource_add) { > - indication = strdup(RASD_IND_CREATED); > - } > - else if (func == &resource_del) { > - indication = strdup(RASD_IND_DELETED); > - } > - else { > - indication = strdup(RASD_IND_MODIFIED); > + indication = RASD_IND_CREATED; > + } else if (func == &resource_del) { > + indication = RASD_IND_DELETED; > + } else { > + indication = RASD_IND_MODIFIED; > char *dummy_name = NULL; > > if (asprintf(&dummy_name, "%s/%s",dominfo->name, > devid) == -1) { > -- > 1.7.7.5 > > _______________________________________________ > Libvirt-cim mailing list > Libvirt-cim at redhat.com > https://www.redhat.com/mailman/listinfo/libvirt-cim > From snmishra at us.ibm.com Wed Jan 18 20:46:39 2012 From: snmishra at us.ibm.com (Sharad Mishra) Date: Wed, 18 Jan 2012 12:46:39 -0800 Subject: [Libvirt-cim] [PATCH v3 0/4] Fix errors raised by Coverity tool In-Reply-To: <1326902772-18178-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326902772-18178-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: +1 Sharad Mishra Open Virtualization Linux Technology Center IBM libvirt-cim-bounces at redhat.com wrote on 01/18/2012 08:06:08 AM: > "Eduardo Lima (Etrunko)" > Sent by: libvirt-cim-bounces at redhat.com > > 01/18/2012 08:06 AM > > Please respond to > List for discussion and development of libvirt CIM > > To > > libvirt-cim at redhat.com > > cc > > "Eduardo Lima \(Etrunko\)" > > Subject > > [Libvirt-cim] [PATCH v3 0/4] Fix errors raised by Coverity tool > > From: "Eduardo Lima (Etrunko)" > > Yet another series of patches fixing errors revealed by Coverity > tool. It would > be nice if we had a similar setup so we could run the tool on a > regular basis. I > started playing with clang a while ago. It also provides a static > analyser, but > I could not complete the setup by then. > > https://bugzilla.redhat.com/show_bug.cgi?id=750418 > > Changes from v2: > - Revert leak change for libxkutil/xmlgen.c in patch 2 which was causing a > double-free crash and correctly fix the leak problem. > > Changes from v1: > - Fix compilation error in Patch 1 > > Best regards, Etrunko > > -- > Eduardo de Barros Lima > Software Engineer, Open Virtualization > Linux Technology Center - IBM/Brazil > eblima at br.ibm.com > > Eduardo Lima (Etrunko) (4): > libxkutil: Fix possible NULL dereferences > Fix possible memory leaks > xml_parse_test: Fix invalid dereference > Fix possible use of unitialized variables > > libxkutil/cs_util_instance.c | 5 +++++ > libxkutil/device_parsing.c | 14 +++++++------- > libxkutil/pool_parsing.c | 5 +++-- > libxkutil/xml_parse_test.c | 3 +-- > libxkutil/xmlgen.c | 8 +++++--- > src/Virt_AppliedFilterList.c | 3 ++- > src/Virt_Device.c | 20 ++++++++++++++++++++ > src/Virt_DevicePool.c | 19 ++++++++++++++++++- > src/Virt_SwitchService.c | 24 +++++++++++++++++++ +---- > src/Virt_VirtualSystemManagementService.c | 16 ++++++++-------- > src/Virt_VirtualSystemSnapshotService.c | 2 +- > 11 files changed, 90 insertions(+), 29 deletions(-) > > -- > 1.7.7.5 > > _______________________________________________ > Libvirt-cim mailing list > Libvirt-cim at redhat.com > https://www.redhat.com/mailman/listinfo/libvirt-cim > From snmishra at us.ibm.com Wed Jan 18 20:47:37 2012 From: snmishra at us.ibm.com (Sharad Mishra) Date: Wed, 18 Jan 2012 12:47:37 -0800 Subject: [Libvirt-cim] [PATCH 3/4] xml_parse_test: Fix invalid dereference In-Reply-To: <1326902772-18178-4-git-send-email-eblima@linux.vnet.ibm.com> References: <1326902772-18178-1-git-send-email-eblima@linux.vnet.ibm.com> <1326902772-18178-4-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: +1 Sharad Mishra Open Virtualization Linux Technology Center IBM libvirt-cim-bounces at redhat.com wrote on 01/18/2012 08:06:11 AM: > "Eduardo Lima (Etrunko)" > Sent by: libvirt-cim-bounces at redhat.com > > 01/18/2012 08:06 AM > > Please respond to > List for discussion and development of libvirt CIM > > To > > libvirt-cim at redhat.com > > cc > > "Eduardo Lima \(Etrunko\)" > > Subject > > [Libvirt-cim] [PATCH 3/4] xml_parse_test: Fix invalid dereference > > From: "Eduardo Lima (Etrunko)" > > As revealed by recent Coverity scan report provided by Red Hat: > https://bugzilla.redhat.com/show_bug.cgi?id=750418 > https://bugzilla.redhat.com/attachment.cgi?id=552325 > > Error: USE_AFTER_FREE: > xml_parse_test.c:239: freed_arg: "free" frees "xml". > xml_parse_test.c:242: pass_freed_arg: Passing freed pointer "xml" as > an argument to function "printf". > > Signed-off-by: Eduardo Lima (Etrunko) > --- > libxkutil/xml_parse_test.c | 3 +-- > 1 files changed, 1 insertions(+), 2 deletions(-) > > diff --git a/libxkutil/xml_parse_test.c b/libxkutil/xml_parse_test.c > index 16ceefb..384593d 100644 > --- a/libxkutil/xml_parse_test.c > +++ b/libxkutil/xml_parse_test.c > @@ -236,11 +236,10 @@ static int dominfo_from_file(const char > *fname, struct domain **d) > > ret = get_dominfo_from_xml(xml, d); > > + printf("XML:\n%s", xml); > free(xml); > fclose(file); > > - printf("XML:\n%s", xml); > - > return ret; > } > > -- > 1.7.7.5 > > _______________________________________________ > Libvirt-cim mailing list > Libvirt-cim at redhat.com > https://www.redhat.com/mailman/listinfo/libvirt-cim > From snmishra at us.ibm.com Wed Jan 18 20:46:59 2012 From: snmishra at us.ibm.com (Sharad Mishra) Date: Wed, 18 Jan 2012 12:46:59 -0800 Subject: [Libvirt-cim] [PATCH 1/4] libxkutil: Fix possible NULL dereferences In-Reply-To: <1326902772-18178-2-git-send-email-eblima@linux.vnet.ibm.com> References: <1326902772-18178-1-git-send-email-eblima@linux.vnet.ibm.com> <1326902772-18178-2-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: +1 Sharad Mishra Open Virtualization Linux Technology Center IBM libvirt-cim-bounces at redhat.com wrote on 01/18/2012 08:06:09 AM: > "Eduardo Lima (Etrunko)" > Sent by: libvirt-cim-bounces at redhat.com > > 01/18/2012 08:06 AM > > Please respond to > List for discussion and development of libvirt CIM > > To > > libvirt-cim at redhat.com > > cc > > "Eduardo Lima \(Etrunko\)" > > Subject > > [Libvirt-cim] [PATCH 1/4] libxkutil: Fix possible NULL dereferences > > From: "Eduardo Lima (Etrunko)" > > As revealed by recent Coverity scan report provided by Red Hat: > https://bugzilla.redhat.com/show_bug.cgi?id=750418 > https://bugzilla.redhat.com/attachment.cgi?id=552325 > > Error: FORWARD_NULL: > xmlgen.c:100: var_compare_op: Comparing "dev->device" to null > implies that "dev->device" might be null. > xmlgen.c:115: var_deref_model: Passing null variable "(char *) > dev->device" to function "__coverity_strcmp", which dereferences it. > > Error: FORWARD_NULL: > device_parsing.c:615: var_compare_op: Comparing "gdev->type" to null > implies that "gdev->type" might be null. > device_parsing.c:677: var_deref_model: Passing null variable > "gdev->type" to function "cleanup_graphics_device", which dereferences it. > device_parsing.c:126: deref_parm_in_call: Function "strcasecmp" > dereferences parameter "dev->type". (The dereference is assumed on > the basis of the 'nonnull' parameter attribute.) > > Error: NULL_RETURNS: > Virt_DevicePool.c:805: returned_null: Function "get_typed_instance" > returns null (checked 37 out of 44 times). > misc_util.c:348: null_assign: Assigning: "inst" = NULL. > misc_util.c:369: return_null_var: Returning "inst", which is null. > Virt_DevicePool.c:805: var_assigned: Assigning: "inst" = null return > value from "get_typed_instance". > Virt_DevicePool.c:810: dereference: Dereferencing a pointer that > might be null "inst" when calling "mempool_set_total". > Virt_DevicePool.c:686: deref_parm: Directly dereferencing parameter "inst". > > Error: NULL_RETURNS: > Virt_DevicePool.c:837: returned_null: Function "get_typed_instance" > returns null (checked 37 out of 44 times). > misc_util.c:348: null_assign: Assigning: "inst" = NULL. > misc_util.c:369: return_null_var: Returning "inst", which is null. > Virt_DevicePool.c:837: var_assigned: Assigning: "inst" = null return > value from "get_typed_instance". > Virt_DevicePool.c:842: dereference: Dereferencing a pointer that > might be null "inst" when calling "procpool_set_total". > Virt_DevicePool.c:743: deref_parm: Directly dereferencing parameter "inst". > > Error: NULL_RETURNS: > Virt_Device.c:219: returned_null: Function "get_typed_instance" > returns null (checked 37 out of 44 times). > misc_util.c:348: null_assign: Assigning: "inst" = NULL. > misc_util.c:369: return_null_var: Returning "inst", which is null. > Virt_Device.c:219: var_assigned: Assigning: "inst" = null return > value from "get_typed_instance". > Virt_Device.c:224: dereference: Dereferencing a pointer that might > be null "inst" when calling "graphics_set_attr". > Virt_Device.c:202: deref_parm: Directly dereferencing parameter "instance". > > Error: NULL_RETURNS: > Virt_Device.c:133: returned_null: Function "get_typed_instance" > returns null (checked 37 out of 44 times). > misc_util.c:348: null_assign: Assigning: "inst" = NULL. > misc_util.c:369: return_null_var: Returning "inst", which is null. > Virt_Device.c:133: var_assigned: Assigning: "inst" = null return > value from "get_typed_instance". > Virt_Device.c:138: dereference: Dereferencing a pointer that might > be null "inst" when calling "disk_set_name". > Virt_Device.c:117: deref_parm: Directly dereferencing parameter "instance". > > Error: NULL_RETURNS: > Virt_Device.c:175: returned_null: Function "get_typed_instance" > returns null (checked 37 out of 44 times). > misc_util.c:348: null_assign: Assigning: "inst" = NULL. > misc_util.c:369: return_null_var: Returning "inst", which is null. > Virt_Device.c:175: var_assigned: Assigning: "inst" = null return > value from "get_typed_instance". > Virt_Device.c:180: dereference: Dereferencing a pointer that might > be null "inst" when calling "mem_set_size". > Virt_Device.c:156: deref_parm: Directly dereferencing parameter "instance". > > Error: NULL_RETURNS: > Virt_Device.c:100: returned_null: Function "get_typed_instance" > returns null (checked 37 out of 44 times). > misc_util.c:348: null_assign: Assigning: "inst" = NULL. > misc_util.c:369: return_null_var: Returning "inst", which is null. > Virt_Device.c:100: var_assigned: Assigning: "inst" = null return > value from "get_typed_instance". > Virt_Device.c:105: dereference: Dereferencing a pointer that might > be null "inst" when calling "net_set_type". > Virt_Device.c:61: deref_parm: Directly dereferencing parameter "instance". > > Signed-off-byr Eduardo Lima (Etrunko) > --- > libxkutil/device_parsing.c | 13 ++++++------- > libxkutil/xmlgen.c | 4 ++-- > src/Virt_Device.c | 20 ++++++++++++++++++++ > src/Virt_DevicePool.c | 14 ++++++++++++++ > 4 files changed, 42 insertions(+), 9 deletions(-) > > diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c > index 7eaa63e..b0eccfc 100644 > --- a/libxkutil/device_parsing.c > +++ b/libxkutil/device_parsing.c > @@ -120,15 +120,14 @@ static void cleanup_sdl_device(struct > graphics_device *dev) > > static void cleanup_graphics_device(struct graphics_device *dev) > { > - if (dev == NULL) > + if (dev == NULL || dev->type == NULL) > return; > > - if (STREQC(dev->type, "sdl")) { > - cleanup_sdl_device(dev); > - } > - else { > - cleanup_vnc_device(dev); > - } > + if (STREQC(dev->type, "sdl")) > + cleanup_sdl_device(dev); > + else > + cleanup_vnc_device(dev); > + > free(dev->type); > } > > diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c > index d73ffd0..96b4e96 100644 > --- a/libxkutil/xmlgen.c > +++ b/libxkutil/xmlgen.c > @@ -112,8 +112,8 @@ static const char *disk_file_xml(xmlNodePtr > root, struct disk_device *dev) > xmlNewProp(tmp, BAD_CAST "cache", BAD_CAST > dev->cache); > } > > - if ((XSTREQ(dev->device, "cdrom")) && > - (XSTREQ(dev->source, ""))) { > + if (dev->device != NULL && XSTREQ(dev->device, "cdrom") && > + XSTREQ(dev->source, "")) { > /* This is the situation that user defined a cdrom > device without > disk in it, so skip generating a line saying > "source", for that > xml defination for libvirt should not have this > defined in this > diff --git a/src/Virt_Device.c b/src/Virt_Device.c > index fd11370..abe3d6f 100644 > --- a/src/Virt_Device.c > +++ b/src/Virt_Device.c > @@ -102,6 +102,11 @@ static CMPIInstance *net_instance(const > CMPIBroker *broker, > "NetworkPort", > ns); > > + if (inst == NULL) { > + CU_DEBUG("Failed to get instance for NetworkPort"); > + return NULL; > + } > + > if (!net_set_type(inst, dev)) > return NULL; > > @@ -135,6 +140,11 @@ static CMPIInstance *disk_instance(const > CMPIBroker *broker, > "LogicalDisk", > ns); > > + if (inst == NULL) { > + CU_DEBUG("Failed to get instance for LogicalDisk"); > + return NULL; > + } > + > if (!disk_set_name(inst, dev)) > return NULL; > > @@ -177,6 +187,11 @@ static CMPIInstance *mem_instance(const > CMPIBroker *broker, > "Memory", > ns); > > + if (inst == NULL) { > + CU_DEBUG("Failed to get instance for Memory"); > + return NULL; > + } > + > if (!mem_set_size(inst, dev)) > return NULL; > > @@ -221,6 +236,11 @@ static CMPIInstance *graphics_instance(const > CMPIBroker *broker, > "DisplayController", > ns); > > + if (inst == NULL) { > + CU_DEBUG("Failed to get instance for DisplayController"); > + return NULL; > + } > + > if (!graphics_set_attr(inst, dev)) > return NULL; > > diff --git a/src/Virt_DevicePool.c b/src/Virt_DevicePool.c > index a41a378..ab0baa0 100644 > --- a/src/Virt_DevicePool.c > +++ b/src/Virt_DevicePool.c > @@ -807,6 +807,13 @@ static CMPIStatus mempool_instance(virConnectPtr conn, > "MemoryPool", > ns); > > + if (inst == NULL) { > + cu_statusf(broker, &s, > + CMPI_RC_ERR_FAILED, > + "Failed to get instance for MemoryPool"); > + return s; > + } > + > mempool_set_total(inst, conn); > mempool_set_consumed(inst, conn); > > @@ -839,6 +846,13 @@ static CMPIStatus procpool_instance(virConnectPtr conn, > "ProcessorPool", > ns); > > + if (inst == NULL) { > + cu_statusf(broker, &s, > + CMPI_RC_ERR_FAILED, > + "Failed to get instance for ProcessorPool"); > + return s; > + } > + > procpool_set_total(inst, conn); > > set_params(inst, CIM_RES_TYPE_PROC, id, "Processors", NULL, true); > -- > 1.7.7.5 > > _______________________________________________ > Libvirt-cim mailing list > Libvirt-cim at redhat.com > https://www.redhat.com/mailman/listinfo/libvirt-cim > From snmishra at us.ibm.com Wed Jan 18 20:47:57 2012 From: snmishra at us.ibm.com (Sharad Mishra) Date: Wed, 18 Jan 2012 12:47:57 -0800 Subject: [Libvirt-cim] [PATCH 4/4] Fix possible use of unitialized variables In-Reply-To: <1326902772-18178-5-git-send-email-eblima@linux.vnet.ibm.com> References: <1326902772-18178-1-git-send-email-eblima@linux.vnet.ibm.com> <1326902772-18178-5-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: +1 Sharad Mishra Open Virtualization Linux Technology Center IBM libvirt-cim-bounces at redhat.com wrote on 01/18/2012 08:06:12 AM: > "Eduardo Lima (Etrunko)" > Sent by: libvirt-cim-bounces at redhat.com > > 01/18/2012 08:06 AM > > Please respond to > List for discussion and development of libvirt CIM > > To > > libvirt-cim at redhat.com > > cc > > "Eduardo Lima \(Etrunko\)" > > Subject > > [Libvirt-cim] [PATCH 4/4] Fix possible use of unitialized variables > > From: "Eduardo Lima (Etrunko)" > > As revealed by recent Coverity scan report provided by Red Hat: > https://bugzilla.redhat.com/show_bug.cgi?id=750418 > https://bugzilla.redhat.com/attachment.cgi?id=552325 > > Error: UNINIT: > Virt_VirtualSystemManagementService.c:2798: var_decl: Declaring > variable "s" without initializer. > Virt_VirtualSystemManagementService.c:2901: uninit_use: Using > uninitialized value "s": field "s".msg is uninitialized. > > Error: UNINIT: > Virt_VirtualSystemSnapshotService.c:393: var_decl: Declaring > variable "s" without initializer. > Virt_VirtualSystemSnapshotService.c:398: uninit_use_in_call: Using > uninitialized value "s.rc" when calling "new_context". > Virt_VirtualSystemSnapshotService.c:378: read_parm_fld: Reading a > parameter field. > > Signed-off-by: Eduardo Lima (Etrunko) > --- > src/Virt_VirtualSystemManagementService.c | 2 +- > src/Virt_VirtualSystemSnapshotService.c | 2 +- > 2 files changed, 2 insertions(+), 2 deletions(-) > > diff --git a/src/Virt_VirtualSystemManagementService.c b/src/ > Virt_VirtualSystemManagementService.c > index 3a0b423..6f42c42 100644 > --- a/src/Virt_VirtualSystemManagementService.c > +++ b/src/Virt_VirtualSystemManagementService.c > @@ -2732,7 +2732,7 @@ static CMPIStatus _update_resources_for(const > CMPIContext *context, > CMPIInstance *rasd, > resmod_fn func) > { > - CMPIStatus s; > + CMPIStatus s = {CMPI_RC_OK, NULL}; > struct domain *dominfo = NULL; > uint16_t type; > char *xml = NULL; > diff --git a/src/Virt_VirtualSystemSnapshotService.c b/src/ > Virt_VirtualSystemSnapshotService.c > index 898fa57..aae628f 100644 > --- a/src/Virt_VirtualSystemSnapshotService.c > +++ b/src/Virt_VirtualSystemSnapshotService.c > @@ -390,7 +390,7 @@ static CMPIStatus start_snapshot_job(const > CMPIObjectPath *ref, > CMPIArgs *argsout) > { > struct snap_context *ctx; > - CMPIStatus s; > + CMPIStatus s = {CMPI_RC_OK, NULL}; > CMPIObjectPath *job; > CMPIObjectPath *vssd; > CMPIInstance *inst; > -- > 1.7.7.5 > > _______________________________________________ > Libvirt-cim mailing list > Libvirt-cim at redhat.com > https://www.redhat.com/mailman/listinfo/libvirt-cim > From snmishra at us.ibm.com Wed Jan 18 22:12:46 2012 From: snmishra at us.ibm.com (Sharad Mishra) Date: Wed, 18 Jan 2012 14:12:46 -0800 Subject: [Libvirt-cim] [V4 PATCH 2/8] vlan library - add missing header files in libnl-devel 1.1 In-Reply-To: <1326879704-12189-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1326879704-12189-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: I guess we are okay including the LGPL code written by others in libvirt-cim. The only issue I see is the one that DV raised earlier ... now it becomes our baby to maintain. Regards, Sharad Mishra Open Virtualization Linux Technology Center IBM libvirt-cim-bounces at redhat.com wrote on 01/18/2012 01:41:44 AM: > Wenchao Xia > Sent by: libvirt-cim-bounces at redhat.com > > 01/18/2012 01:41 AM > > Please respond to > List for discussion and development of libvirt CIM > > To > > libvirt-cim at redhat.com > > cc > > Wenchao Xia > > Subject > > [Libvirt-cim] [V4 PATCH 2/8] vlan library - add missing header files > in libnl-devel 1.1 > > Because libnl-devel-1.1 package missed some header files even iffunctions > are included in its .so file, they are directly be put here. Codes > are from the > help documents that libnl-devel-1.1 provides. > > Signed-off-by: Wenchao Xia > --- > libnetwork/include/netlink/route/link/info-api.h | 71 +++++++++++ > +++++++++++ > libnetwork/include/netlink/route/link/vlan.h | 55 ++++++++++++++++ + > 2 files changed, 126 insertions(+), 0 deletions(-) > create mode 100644 libnetwork/include/netlink/route/link/info-api.h > create mode 100644 libnetwork/include/netlink/route/link/vlan.h > > diff --git a/libnetwork/include/netlink/route/link/info-api.h b/ > libnetwork/include/netlink/route/link/info-api.h > new file mode 100644 > index 0000000..7a2e498 > --- /dev/null > +++ b/libnetwork/include/netlink/route/link/info-api.h > @@ -0,0 +1,71 @@ > +/* > + * netlink/route/link/info-api.h Link Info API > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation version 2.1 > + * of the License. > + * > + * Copyright (c) 2003-2008 Thomas Graf > + */ > + > +#ifndef NETLINK_LINK_INFO_API_H_ > +#define NETLINK_LINK_INFO_API_H_ > + > +#include > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +/** > + * @ingroup link_info > + * > + * Link info operations > + */ > +struct rtnl_link_info_ops > +{ > + /** Name of operations, must match name on kernel side */ > + char * io_name; > + > + /** Reference count (internal, do not use) */ > + int io_refcnt; > + > + /** Called to assign an info type to a link. > + * Has to allocate enough resources to hold attributes. Can > + * use link->l_info to store a pointer. */ > + int (*io_alloc)(struct rtnl_link *); > + > + /** Called to parse the link info attribute. > + * Must parse the attribute and assign all values to the link. > + */ > + int (*io_parse)(struct rtnl_link *, > + struct nlattr *, > + struct nlattr *); > + > + /** Called when the link object is dumped. > + * Must dump the info type specific attributes. */ > + int (*io_dump[NL_DUMP_MAX+1])(struct rtnl_link *, > + struct > nl_dump_params *, int); > + > + /** Called when a link object is cloned. > + * Must clone all info type specific attributes. */ > + int (*io_clone)(struct rtnl_link *, struct rtnl_link *); > + > + /** Called when construction a link netlink message. > + * Must append all info type specific attributes to the message. */ > + int (*io_put_attrs)(struct nl_msg *, struct rtnl_link *); > + > + /** Called to release all resources previously allocated > + * in either io_alloc() or io_parse(). */ > + void (*io_free)(struct rtnl_link *); > + > + struct rtnl_link_info_ops * io_next; > +}; > + > +extern struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *); > + > +extern int rtnl_link_register_info(struct > rtnl_link_info_ops *); > +extern int rtnl_link_unregister_info(struct > rtnl_link_info_ops *); > + > +#endif > diff --git a/libnetwork/include/netlink/route/link/vlan.h b/ > libnetwork/include/netlink/route/link/vlan.h > new file mode 100644 > index 0000000..80aa921 > --- /dev/null > +++ b/libnetwork/include/netlink/route/link/vlan.h > @@ -0,0 +1,55 @@ > +/* > + * netlink/route/link/vlan.h VLAN interface > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation version 2.1 > + * of the License. > + * > + * Copyright (c) 2003-2008 Thomas Graf > + */ > + > +#ifndef NETLINK_LINK_VLAN_H_ > +#define NETLINK_LINK_VLAN_H_ > + > +#include > +#include > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +struct vlan_map > +{ > + uint32_t vm_from; > + uint32_t vm_to; > +}; > + > +#define VLAN_PRIO_MAX 7 > + > +extern char * rtnl_link_vlan_flags2str(int, char *, size_t); > +extern int rtnl_link_vlan_str2flags(const char *); > + > +extern int rtnl_link_vlan_set_id(struct rtnl_link *, int); > +extern int rtnl_link_vlan_get_id(struct rtnl_link *); > + > +extern int rtnl_link_vlan_set_flags(struct rtnl_link *, > + unsigned int); > +extern int rtnl_link_vlan_unset_flags(struct rtnl_link *, > + unsigned int); > +extern unsigned int rtnl_link_vlan_get_flags(struct rtnl_link *); > + > +extern int rtnl_link_vlan_set_ingress_map(struct rtnl_link *, > + int, uint32_t); > +extern uint32_t * rtnl_link_vlan_get_ingress_map(struct rtnl_link *); > + > +extern int rtnl_link_vlan_set_egress_map(struct rtnl_link *, > + uint32_t, int); > +extern struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *, > + int *); > + > +#ifdef __cplusplus > +} > +#endif > + > +#endif > -- > 1.7.1 > > > _______________________________________________ > Libvirt-cim mailing list > Libvirt-cim at redhat.com > https://www.redhat.com/mailman/listinfo/libvirt-cim > From cvincent at linux.vnet.ibm.com Thu Jan 19 01:04:55 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Wed, 18 Jan 2012 20:04:55 -0500 Subject: [Libvirt-cim] [V4 PATCH 2/8] vlan library - add missing header files in libnl-devel 1.1 In-Reply-To: References: <1326879704-12189-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <4F176C37.6080707@linux.vnet.ibm.com> I installed the package and the file is indeed missing even though it is advertised by the rpm (I'm using RHEL 6.2--is this bug in other distros?). As such, I don't see another option short of manually creating them, which is also ours to maintain.IMO, you might as well place this in the libxkutil directory where we keep the other general purpose headers. On 01/18/2012 05:12 PM, Sharad Mishra wrote: > I guess we are okay including the LGPL code written by others in > libvirt-cim. The only issue I see is the one that DV raised earlier ... now > it becomes our baby to maintain. > > Regards, > Sharad Mishra > Open Virtualization > Linux Technology Center > IBM > > libvirt-cim-bounces at redhat.com wrote on 01/18/2012 01:41:44 AM: > >> Wenchao Xia >> Sent by: libvirt-cim-bounces at redhat.com >> >> 01/18/2012 01:41 AM >> >> Please respond to >> List for discussion and development of libvirt CIM > >> To >> >> libvirt-cim at redhat.com >> >> cc >> >> Wenchao Xia >> >> Subject >> >> [Libvirt-cim] [V4 PATCH 2/8] vlan library - add missing header files >> in libnl-devel 1.1 >> >> Because libnl-devel-1.1 package missed some header files even > iffunctions >> are included in its .so file, they are directly be put here. Codes >> are from the >> help documents that libnl-devel-1.1 provides. >> >> Signed-off-by: Wenchao Xia >> --- >> libnetwork/include/netlink/route/link/info-api.h | 71 +++++++++++ >> +++++++++++ >> libnetwork/include/netlink/route/link/vlan.h | 55 ++++++++++++++++ > + >> 2 files changed, 126 insertions(+), 0 deletions(-) >> create mode 100644 libnetwork/include/netlink/route/link/info-api.h >> create mode 100644 libnetwork/include/netlink/route/link/vlan.h >> >> diff --git a/libnetwork/include/netlink/route/link/info-api.h b/ >> libnetwork/include/netlink/route/link/info-api.h >> new file mode 100644 >> index 0000000..7a2e498 >> --- /dev/null >> +++ b/libnetwork/include/netlink/route/link/info-api.h >> @@ -0,0 +1,71 @@ >> +/* >> + * netlink/route/link/info-api.h Link Info API >> + * >> + * This library is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU Lesser General Public >> + * License as published by the Free Software Foundation version 2.1 >> + * of the License. >> + * >> + * Copyright (c) 2003-2008 Thomas Graf >> + */ >> + >> +#ifndefNETLINK_LINK_INFO_API_H_ >> +#define NETLINK_LINK_INFO_API_H_ >> + >> +#include >> + >> +#ifdef __cplusplus >> +extern "C" { >> +#endif >> + >> +/** >> + * @ingroup link_info >> + * >> + * Link info operations >> + */ >> +struct rtnl_link_info_ops >> +{ >> + /** Name of operations, must match name on kernel side */ >> + char * io_name; >> + >> + /** Reference count (internal, do not use) */ >> + int io_refcnt; >> + >> + /** Called to assign an info type to a link. >> + * Has to allocate enough resources to hold attributes. Can >> + * use link->l_info to store a pointer. */ >> + int (*io_alloc)(struct rtnl_link *); >> + >> + /** Called to parse the link info attribute. >> + * Must parse the attribute and assign all values to the link. >> + */ >> + int (*io_parse)(struct rtnl_link *, >> + struct nlattr *, >> + struct nlattr *); >> + >> + /** Called when the link object is dumped. >> + * Must dump the info type specific attributes. */ >> + int (*io_dump[NL_DUMP_MAX+1])(struct rtnl_link *, >> + struct >> nl_dump_params *, int); >> + >> + /** Called when a link object is cloned. >> + * Must clone all info type specific attributes. */ >> + int (*io_clone)(struct rtnl_link *, struct rtnl_link > *); >> + >> + /** Called when construction a link netlink message. >> + * Must append all info type specific attributes to the message. > */ >> + int (*io_put_attrs)(struct nl_msg *, struct rtnl_link > *); >> + >> + /** Called to release all resources previously allocated >> + * in either io_alloc() or io_parse(). */ >> + void (*io_free)(struct rtnl_link *); >> + >> + struct rtnl_link_info_ops * io_next; >> +}; >> + >> +extern struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char > *); >> + >> +extern int rtnl_link_register_info(struct >> rtnl_link_info_ops *); >> +extern int rtnl_link_unregister_info(struct >> rtnl_link_info_ops *); >> + >> +#endif >> diff --git a/libnetwork/include/netlink/route/link/vlan.h b/ >> libnetwork/include/netlink/route/link/vlan.h >> new file mode 100644 >> index 0000000..80aa921 >> --- /dev/null >> +++ b/libnetwork/include/netlink/route/link/vlan.h >> @@ -0,0 +1,55 @@ >> +/* >> + * netlink/route/link/vlan.h VLAN interface >> + * >> + * This library is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU Lesser General Public >> + * License as published by the Free Software Foundation version 2.1 >> + * of the License. >> + * >> + * Copyright (c) 2003-2008 Thomas Graf >> + */ >> + >> +#ifndef NETLINK_LINK_VLAN_H_ >> +#define NETLINK_LINK_VLAN_H_ >> + >> +#include >> +#include >> + >> +#ifdef __cplusplus >> +extern "C" { >> +#endif >> + >> +struct vlan_map >> +{ >> + uint32_t vm_from; >> + uint32_t vm_to; >> +}; >> + >> +#define VLAN_PRIO_MAX 7 >> + >> +extern char * rtnl_link_vlan_flags2str(int, char *, size_t); >> +extern int rtnl_link_vlan_str2flags(const char *); >> + >> +extern int rtnl_link_vlan_set_id(struct rtnl_link *, int); >> +extern int rtnl_link_vlan_get_id(struct rtnl_link *); >> + >> +extern int rtnl_link_vlan_set_flags(struct rtnl_link *, >> + unsigned int); >> +extern int rtnl_link_vlan_unset_flags(struct rtnl_link *, >> + unsigned int); >> +extern unsigned int rtnl_link_vlan_get_flags(struct rtnl_link *); >> + >> +extern int rtnl_link_vlan_set_ingress_map(struct rtnl_link > *, >> + int, uint32_t); >> +extern uint32_t * rtnl_link_vlan_get_ingress_map(struct rtnl_link > *); >> + >> +extern int rtnl_link_vlan_set_egress_map(struct rtnl_link > *, >> + uint32_t, int); >> +extern struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link > *, >> + int *); >> + >> +#ifdef __cplusplus >> +} >> +#endif >> + >> +#endif >> -- >> 1.7.1 >> >> >> _______________________________________________ >> Libvirt-cim mailing list >> Libvirt-cim at redhat.com >> https://www.redhat.com/mailman/listinfo/libvirt-cim >> > _______________________________________________ > Libvirt-cim mailing list > Libvirt-cim at redhat.com > https://www.redhat.com/mailman/listinfo/libvirt-cim > -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From xiawenc at linux.vnet.ibm.com Thu Jan 19 03:09:22 2012 From: xiawenc at linux.vnet.ibm.com (Wayne Xia) Date: Thu, 19 Jan 2012 11:09:22 +0800 Subject: [Libvirt-cim] [V4 PATCH 2/8] vlan library - add missing header files in libnl-devel 1.1 In-Reply-To: <4F176C37.6080707@linux.vnet.ibm.com> References: <1326879704-12189-1-git-send-email-xiawenc@linux.vnet.ibm.com> <4F176C37.6080707@linux.vnet.ibm.com> Message-ID: <4F178962.8080201@linux.vnet.ibm.com> ? 2012-1-19 9:04, Chip Vincent ??: > I installed the package and the file is indeed missing even though it is > advertised by the rpm (I'm using RHEL 6.2--is this bug in other > distros?). As such, I don't see another option short of manually > creating them, which is also ours to maintain.IMO, you might as well > place this in the libxkutil directory where we keep the other general > purpose headers. > it is a burden to take care of the baby header files by ourself, but I think libnl-1 project have stopped to release newer version, instead they are working on libnl-3, so these header files would not need to be updated in the future, if we use libnl-1. > On 01/18/2012 05:12 PM, Sharad Mishra wrote: >> I guess we are okay including the LGPL code written by others in >> libvirt-cim. The only issue I see is the one that DV raised earlier >> ... now >> it becomes our baby to maintain. >> >> Regards, >> Sharad Mishra >> Open Virtualization >> Linux Technology Center >> IBM >> >> libvirt-cim-bounces at redhat.com wrote on 01/18/2012 01:41:44 AM: >> >>> Wenchao Xia >>> Sent by: libvirt-cim-bounces at redhat.com >>> >>> 01/18/2012 01:41 AM >>> >>> Please respond to >>> List for discussion and development of libvirt CIM >> >>> To >>> >>> libvirt-cim at redhat.com >>> >>> cc >>> >>> Wenchao Xia >>> >>> Subject >>> >>> [Libvirt-cim] [V4 PATCH 2/8] vlan library - add missing header files >>> in libnl-devel 1.1 >>> >>> Because libnl-devel-1.1 package missed some header files even >> iffunctions >>> are included in its .so file, they are directly be put here. Codes >>> are from the >>> help documents that libnl-devel-1.1 provides. >>> >>> Signed-off-by: Wenchao Xia >>> --- >>> libnetwork/include/netlink/route/link/info-api.h | 71 +++++++++++ >>> +++++++++++ >>> libnetwork/include/netlink/route/link/vlan.h | 55 ++++++++++++++++ >> + >>> 2 files changed, 126 insertions(+), 0 deletions(-) >>> create mode 100644 libnetwork/include/netlink/route/link/info-api.h >>> create mode 100644 libnetwork/include/netlink/route/link/vlan.h >>> >>> diff --git a/libnetwork/include/netlink/route/link/info-api.h b/ >>> libnetwork/include/netlink/route/link/info-api.h >>> new file mode 100644 >>> index 0000000..7a2e498 >>> --- /dev/null >>> +++ b/libnetwork/include/netlink/route/link/info-api.h >>> @@ -0,0 +1,71 @@ >>> +/* >>> + * netlink/route/link/info-api.h Link Info API >>> + * >>> + * This library is free software; you can redistribute it and/or >>> + * modify it under the terms of the GNU Lesser General Public >>> + * License as published by the Free Software Foundation version 2.1 >>> + * of the License. >>> + * >>> + * Copyright (c) 2003-2008 Thomas Graf >>> + */ >>> + >>> +#ifndefNETLINK_LINK_INFO_API_H_ >>> +#define NETLINK_LINK_INFO_API_H_ >>> + >>> +#include >>> + >>> +#ifdef __cplusplus >>> +extern "C" { >>> +#endif >>> + >>> +/** >>> + * @ingroup link_info >>> + * >>> + * Link info operations >>> + */ >>> +struct rtnl_link_info_ops >>> +{ >>> + /** Name of operations, must match name on kernel side */ >>> + char * io_name; >>> + >>> + /** Reference count (internal, do not use) */ >>> + int io_refcnt; >>> + >>> + /** Called to assign an info type to a link. >>> + * Has to allocate enough resources to hold attributes. Can >>> + * use link->l_info to store a pointer. */ >>> + int (*io_alloc)(struct rtnl_link *); >>> + >>> + /** Called to parse the link info attribute. >>> + * Must parse the attribute and assign all values to the link. >>> + */ >>> + int (*io_parse)(struct rtnl_link *, >>> + struct nlattr *, >>> + struct nlattr *); >>> + >>> + /** Called when the link object is dumped. >>> + * Must dump the info type specific attributes. */ >>> + int (*io_dump[NL_DUMP_MAX+1])(struct rtnl_link *, >>> + struct >>> nl_dump_params *, int); >>> + >>> + /** Called when a link object is cloned. >>> + * Must clone all info type specific attributes. */ >>> + int (*io_clone)(struct rtnl_link *, struct rtnl_link >> *); >>> + >>> + /** Called when construction a link netlink message. >>> + * Must append all info type specific attributes to the message. >> */ >>> + int (*io_put_attrs)(struct nl_msg *, struct rtnl_link >> *); >>> + >>> + /** Called to release all resources previously allocated >>> + * in either io_alloc() or io_parse(). */ >>> + void (*io_free)(struct rtnl_link *); >>> + >>> + struct rtnl_link_info_ops * io_next; >>> +}; >>> + >>> +extern struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char >> *); >>> + >>> +extern int rtnl_link_register_info(struct >>> rtnl_link_info_ops *); >>> +extern int rtnl_link_unregister_info(struct >>> rtnl_link_info_ops *); >>> + >>> +#endif >>> diff --git a/libnetwork/include/netlink/route/link/vlan.h b/ >>> libnetwork/include/netlink/route/link/vlan.h >>> new file mode 100644 >>> index 0000000..80aa921 >>> --- /dev/null >>> +++ b/libnetwork/include/netlink/route/link/vlan.h >>> @@ -0,0 +1,55 @@ >>> +/* >>> + * netlink/route/link/vlan.h VLAN interface >>> + * >>> + * This library is free software; you can redistribute it and/or >>> + * modify it under the terms of the GNU Lesser General Public >>> + * License as published by the Free Software Foundation version 2.1 >>> + * of the License. >>> + * >>> + * Copyright (c) 2003-2008 Thomas Graf >>> + */ >>> + >>> +#ifndef NETLINK_LINK_VLAN_H_ >>> +#define NETLINK_LINK_VLAN_H_ >>> + >>> +#include >>> +#include >>> + >>> +#ifdef __cplusplus >>> +extern "C" { >>> +#endif >>> + >>> +struct vlan_map >>> +{ >>> + uint32_t vm_from; >>> + uint32_t vm_to; >>> +}; >>> + >>> +#define VLAN_PRIO_MAX 7 >>> + >>> +extern char * rtnl_link_vlan_flags2str(int, char *, size_t); >>> +extern int rtnl_link_vlan_str2flags(const char *); >>> + >>> +extern int rtnl_link_vlan_set_id(struct rtnl_link *, int); >>> +extern int rtnl_link_vlan_get_id(struct rtnl_link *); >>> + >>> +extern int rtnl_link_vlan_set_flags(struct rtnl_link *, >>> + unsigned int); >>> +extern int rtnl_link_vlan_unset_flags(struct rtnl_link *, >>> + unsigned int); >>> +extern unsigned int rtnl_link_vlan_get_flags(struct rtnl_link *); >>> + >>> +extern int rtnl_link_vlan_set_ingress_map(struct rtnl_link >> *, >>> + int, uint32_t); >>> +extern uint32_t * rtnl_link_vlan_get_ingress_map(struct rtnl_link >> *); >>> + >>> +extern int rtnl_link_vlan_set_egress_map(struct rtnl_link >> *, >>> + uint32_t, int); >>> +extern struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link >> *, >>> + int *); >>> + >>> +#ifdef __cplusplus >>> +} >>> +#endif >>> + >>> +#endif >>> -- >>> 1.7.1 >>> >>> >>> _______________________________________________ >>> Libvirt-cim mailing list >>> Libvirt-cim at redhat.com >>> https://www.redhat.com/mailman/listinfo/libvirt-cim >>> >> _______________________________________________ >> Libvirt-cim mailing list >> Libvirt-cim at redhat.com >> https://www.redhat.com/mailman/listinfo/libvirt-cim >> > > -- Best Regards Wayne Xia mail:xiawenc at linux.vnet.ibm.com tel:86-010-82450803 From snmishra at us.ibm.com Thu Jan 19 19:06:57 2012 From: snmishra at us.ibm.com (Sharad Mishra) Date: Thu, 19 Jan 2012 11:06:57 -0800 Subject: [Libvirt-cim] [V4 PATCH 3/8] vlan library - add a simple implemention for bridge In-Reply-To: <1326879720-12235-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1326879720-12235-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: libvirt-cim-bounces at redhat.com wrote on 01/18/2012 01:42:00 AM: > Wenchao Xia > Sent by: libvirt-cim-bounces at redhat.com > > 01/18/2012 01:42 AM > > Please respond to > List for discussion and development of libvirt CIM > > To > > libvirt-cim at redhat.com > > cc > > Wenchao Xia > > Subject > > [Libvirt-cim] [V4 PATCH 3/8] vlan library - add a simple > implemention for bridge > > This patch use ioctl to get bridge settings from kernel. Netlink protocol > can't be used for bridge in linux2.6 kernel. > ioctl is the oldest way to talk to kernel about bridge, so it have some > limit in the ports number and bridge number. Currently they are set to 1024. > > Signed-off-by: Wenchao Xia > --- > libnetwork/host_network_implement_bridge.c | 224 +++++++++++++++++ > +++++++++++ > libnetwork/host_network_implement_bridge.h | 8 + > 2 files changed, 232 insertions(+), 0 deletions(-) > create mode 100644 libnetwork/host_network_implement_bridge.c > create mode 100644 libnetwork/host_network_implement_bridge.h > > diff --git a/libnetwork/host_network_implement_bridge.c b/ > libnetwork/host_network_implement_bridge.c > new file mode 100644 > index 0000000..39c6b13 > --- /dev/null > +++ b/libnetwork/host_network_implement_bridge.c > @@ -0,0 +1,224 @@ > +/* > + * Copyright IBM Corp. 2012 > + * > + * Authors: > + * Wenchao Xia > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "host_network_implement_bridge.h" > +#include "host_network_helper.h" > +#include "host_network_error.h" > + > +/* following number can't be changed otherwise ioctl get errors */ > +#define BR_NUM_MAX 1024 > +#define PORT_NUM_MAX 1024 > +#define NAME_BUFF_SIZE 16 > + > +static int socket_br = -1; > + > +static int try_socket_init(void) > +{ > + if (socket_br < 0) { > + if ((socket_br = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) > + return -errno; Why return -errno? > + } > + return 1; > +} > + > +void try_socket_close(void) > +{ > + if (socket_br > 0) { > + close(socket_br); > + socket_br = -1; > + } > +} > + > +static int get_bridge_ports(EthIface *piface) > +{ > + struct ifreq req; > + char ifname[NAME_BUFF_SIZE]; > + int if_indexes[PORT_NUM_MAX]; > + unsigned long args[4]; > + int i, ret = ERR_LIBBR; > + BR_Prop *pbr; > + > + memset(ifname, 0, sizeof(ifname)); > + memset(&req, 0 ,sizeof(req)); > + memset(if_indexes, 0 ,sizeof(if_indexes)); > + args[0] = BRCTL_GET_PORT_LIST; > + args[1] = (unsigned long)if_indexes; > + args[2] = PORT_NUM_MAX; > + args[3] = 0; > + > + strncpy(req.ifr_name, piface->name, NAME_BUFF_SIZE); > + req.ifr_data = (char *) &args; > + > + if (0 > ioctl(socket_br, SIOCDEVPRIVATE, &req)) { convention used by libvirt-cim is - if (ioctl(socket_br, SIOCDEVPRIVATE, &req) > 0) { > + CU_DEBUG("failed in ioctl listing ports of bridge %s," > + " errno %d, reason %s.", > + piface->name, errno, strerror(errno)); > + goto out; > + } > + > + if (piface->pbr_prop == NULL) { > + eth_iface_add_br_prop(piface); > + } > + pbr = piface->pbr_prop; > + > + i = -1; > + while (i < PORT_NUM_MAX) { > + i++; > + if (if_indexes[i] <= 0) { > + continue; > + } > + if (0 == if_indextoname(if_indexes[i], ifname)) { same as above > + CU_DEBUG("failed to translate if_index %d, skip it.", if_indexes); > + continue; > + } > + /* add the ports to the list */ > + if (pbr->port_names == NULL) { > + SAFE_CALLOC(pbr->port_names, > + MAX_IFACE_NUM, sizeof(char *)); Where do we free this memory? > + pbr->port_num = 0; > + } > + if (pbr->port_num >= MAX_IFACE_NUM) { > + CU_DEBUG("bridge [%s] have too much eth attached!", > piface->name); > + ret = ERR_DEVICE_EXCEED_MAXNUM; > + goto out; > + } > + pbr->port_names[pbr->port_num] = SAFE_STRDUP(ifname); > + pbr->port_num++; > + } > + > + ret = 1; > + > + out: > + return ret; > +} > + > +static int get_bridge_info(EthIface *piface) > +{ > + struct ifreq req; > + struct __bridge_info binfo; > + unsigned long args[4]; > + int ret = ERR_LIBBR; > + > + memset(&req, 0, sizeof(req)); > + memset(&binfo, 0, sizeof(binfo)); > + args[0] = BRCTL_GET_BRIDGE_INFO; > + args[1] = (unsigned long) &binfo; > + args[2] = 0; > + args[3] = 0; > + req.ifr_data = (char *) &args; > + > + if (piface->name == NULL) { > + CU_DEBUG("bridge name not set for ioctl."); > + goto out; > + } > + strncpy(req.ifr_name, piface->name, NAME_BUFF_SIZE); > + if (ioctl(socket_br, SIOCDEVPRIVATE, &req) < 0) { > + CU_DEBUG("failed to get info for %s, errno %d, reason %s.", > + piface->name, errno, strerror(errno)); > + goto out; > + } > + > + if (piface->pbr_prop == NULL) { > + eth_iface_add_br_prop(piface); > + } > + piface->pbr_prop->STP = binfo.stp_enabled; > + > + ret = 1; > + > + out: > + return ret; > +} > + > +static int list_bridges(EthIfacesList *plist) > +{ > + int if_indexes[BR_NUM_MAX]; > + unsigned long args[3]; > + int brnum; > + int i, ret = ERR_LIBBR; > + EthIface tface; > + > + eth_iface_init(&tface); > + SAFE_CALLOC(tface.name, NAME_BUFF_SIZE, 1); free? > + > + args[0] = BRCTL_GET_BRIDGES; > + args[1] = (unsigned long)if_indexes; > + args[2] = BR_NUM_MAX; > + memset(if_indexes, 0, sizeof(if_indexes)); > + > + if (0 > try_socket_init()) { convention > + CU_DEBUG("failed to init socket for bridge ioctl," > + " errno is %d, reason: %s.", > + errno, strerror(errno)); > + goto out; > + } > + > + brnum = ioctl(socket_br, SIOCGIFBR, args); > + if (brnum < 0) { > + CU_DEBUG("failed tp get bridge, errno is %d, reason: %s.", > + errno, strerror(errno)); > + goto out; > + } > + > + i = 0; > + while (i < brnum) { > + if (!if_indextoname(if_indexes[i], tface.name)) { > + CU_DEBUG("failed to translate index %d, errno is %d, > reason: %s.", > + if_indexes[i], errno, strerror(errno)); > + goto out; > + } > + > + ret = get_bridge_info(&tface); > + if (ret != 1) { > + CU_DEBUG("failed to get info for %s.", tface.name); > + continue; > + } > + > + ret = get_bridge_ports(&tface); > + if (ret != 1) { > + CU_DEBUG("failed to get info for %s.", tface.name); > + continue; > + } > + > + if (1 != eth_ifaceslist_add(plist, &tface)) { convention > + CU_DEBUG("failed to add device to list."); > + goto out; > + } > + eth_iface_uninit(&tface); > + eth_iface_init(&tface); > + SAFE_CALLOC(tface.name, NAME_BUFF_SIZE, 1); free? > + i++; > + } > + ret = 1; > + > + out: > + eth_iface_uninit(&tface); > + try_socket_close(); > + return ret; > + > +} > + > +int get_host_eth_ifaces_osapi_bridge(EthIfacesList *plist) > +{ > + return list_bridges(plist); > +} > diff --git a/libnetwork/host_network_implement_bridge.h b/ > libnetwork/host_network_implement_bridge.h > new file mode 100644 > index 0000000..ed77195 > --- /dev/null > +++ b/libnetwork/host_network_implement_bridge.h > @@ -0,0 +1,8 @@ > +#ifndef HOST_NETWORK_IMPLE_BRIDGE_H > +#define HOST_NETWORK_IMPLE_BRIDGE_H > + > +#include "host_network_basic.h" > + > +int get_host_eth_ifaces_osapi_bridge(EthIfacesList *plist); > + > +#endif > -- > 1.7.1 > > > _______________________________________________ > Libvirt-cim mailing list > Libvirt-cim at redhat.com > https://www.redhat.com/mailman/listinfo/libvirt-cim > From xiawenc at linux.vnet.ibm.com Fri Jan 20 01:52:07 2012 From: xiawenc at linux.vnet.ibm.com (Wayne Xia) Date: Fri, 20 Jan 2012 09:52:07 +0800 Subject: [Libvirt-cim] [V4 PATCH 3/8] vlan library - add a simple implemention for bridge In-Reply-To: References: <1326879720-12235-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <4F18C8C7.5060804@linux.vnet.ibm.com> Thank u for reviewing my codes.:) ? 2012-1-20 3:06, Sharad Mishra ??: > > libvirt-cim-bounces at redhat.com wrote on 01/18/2012 01:42:00 AM: > >> Wenchao Xia >> Sent by: libvirt-cim-bounces at redhat.com >> >> 01/18/2012 01:42 AM >> >> Please respond to >> List for discussion and development of libvirt CIM > >> >> To >> >> libvirt-cim at redhat.com >> >> cc >> >> Wenchao Xia >> >> Subject >> >> [Libvirt-cim] [V4 PATCH 3/8] vlan library - add a simple >> implemention for bridge >> >> This patch use ioctl to get bridge settings from kernel. Netlink > protocol >> can't be used for bridge in linux2.6 kernel. >> ioctl is the oldest way to talk to kernel about bridge, so it have > some >> limit in the ports number and bridge number. Currently they are set to > 1024. >> >> Signed-off-by: Wenchao Xia >> --- >> libnetwork/host_network_implement_bridge.c | 224 +++++++++++++++++ >> +++++++++++ >> libnetwork/host_network_implement_bridge.h | 8 + >> 2 files changed, 232 insertions(+), 0 deletions(-) >> create mode 100644 libnetwork/host_network_implement_bridge.c >> create mode 100644 libnetwork/host_network_implement_bridge.h >> >> diff --git a/libnetwork/host_network_implement_bridge.c b/ >> libnetwork/host_network_implement_bridge.c >> new file mode 100644 >> index 0000000..39c6b13 >> --- /dev/null >> +++ b/libnetwork/host_network_implement_bridge.c >> @@ -0,0 +1,224 @@ >> +/* >> + * Copyright IBM Corp. 2012 >> + * >> + * Authors: >> + * Wenchao Xia >> + * >> + * This library is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU Lesser General Public >> + * License as published by the Free Software Foundation; either >> + * version 2.1 of the License, or (at your option) any later version. >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include "host_network_implement_bridge.h" >> +#include "host_network_helper.h" >> +#include "host_network_error.h" >> + >> +/* following number can't be changed otherwise ioctl get errors */ >> +#define BR_NUM_MAX 1024 >> +#define PORT_NUM_MAX 1024 >> +#define NAME_BUFF_SIZE 16 >> + >> +static int socket_br = -1; >> + >> +static int try_socket_init(void) >> +{ >> + if (socket_br< 0) { >> + if ((socket_br = socket(AF_LOCAL, SOCK_STREAM, 0))< 0) >> + return -errno; > > Why return -errno? > my mistake, errno did not need to be returned. >> + } >> + return 1; >> +} >> + >> +void try_socket_close(void) >> +{ >> + if (socket_br> 0) { >> + close(socket_br); >> + socket_br = -1; >> + } >> +} >> + >> +static int get_bridge_ports(EthIface *piface) >> +{ >> + struct ifreq req; >> + char ifname[NAME_BUFF_SIZE]; >> + int if_indexes[PORT_NUM_MAX]; >> + unsigned long args[4]; >> + int i, ret = ERR_LIBBR; >> + BR_Prop *pbr; >> + >> + memset(ifname, 0, sizeof(ifname)); >> + memset(&req, 0 ,sizeof(req)); >> + memset(if_indexes, 0 ,sizeof(if_indexes)); >> + args[0] = BRCTL_GET_PORT_LIST; >> + args[1] = (unsigned long)if_indexes; >> + args[2] = PORT_NUM_MAX; >> + args[3] = 0; >> + >> + strncpy(req.ifr_name, piface->name, NAME_BUFF_SIZE); >> + req.ifr_data = (char *)&args; >> + >> + if (0> ioctl(socket_br, SIOCDEVPRIVATE,&req)) { > > convention used by libvirt-cim is - if (ioctl(socket_br, SIOCDEVPRIVATE, > &req)> 0) { > right. >> + CU_DEBUG("failed in ioctl listing ports of bridge %s," >> + " errno %d, reason %s.", >> + piface->name, errno, strerror(errno)); >> + goto out; >> + } >> + >> + if (piface->pbr_prop == NULL) { >> + eth_iface_add_br_prop(piface); >> + } >> + pbr = piface->pbr_prop; >> + >> + i = -1; >> + while (i< PORT_NUM_MAX) { >> + i++; >> + if (if_indexes[i]<= 0) { >> + continue; >> + } >> + if (0 == if_indextoname(if_indexes[i], ifname)) { > > same as above > >> + CU_DEBUG("failed to translate if_index %d, skip it.", > if_indexes); >> + continue; >> + } >> + /* add the ports to the list */ >> + if (pbr->port_names == NULL) { >> + SAFE_CALLOC(pbr->port_names, >> + MAX_IFACE_NUM, sizeof(char *)); > > Where do we free this memory? > the pointer have beed added to struct EthIface, so un-init function of EthIface would free it. >> + pbr->port_num = 0; >> + } >> + if (pbr->port_num>= MAX_IFACE_NUM) { >> + CU_DEBUG("bridge [%s] have too much eth attached!", >> piface->name); >> + ret = ERR_DEVICE_EXCEED_MAXNUM; >> + goto out; >> + } >> + pbr->port_names[pbr->port_num] = SAFE_STRDUP(ifname); >> + pbr->port_num++; >> + } >> + >> + ret = 1; >> + >> + out: >> + return ret; >> +} >> + >> +static int get_bridge_info(EthIface *piface) >> +{ >> + struct ifreq req; >> + struct __bridge_info binfo; >> + unsigned long args[4]; >> + int ret = ERR_LIBBR; >> + >> + memset(&req, 0, sizeof(req)); >> + memset(&binfo, 0, sizeof(binfo)); >> + args[0] = BRCTL_GET_BRIDGE_INFO; >> + args[1] = (unsigned long)&binfo; >> + args[2] = 0; >> + args[3] = 0; >> + req.ifr_data = (char *)&args; >> + >> + if (piface->name == NULL) { >> + CU_DEBUG("bridge name not set for ioctl."); >> + goto out; >> + } >> + strncpy(req.ifr_name, piface->name, NAME_BUFF_SIZE); >> + if (ioctl(socket_br, SIOCDEVPRIVATE,&req)< 0) { >> + CU_DEBUG("failed to get info for %s, errno %d, reason %s.", >> + piface->name, errno, strerror(errno)); >> + goto out; >> + } >> + >> + if (piface->pbr_prop == NULL) { >> + eth_iface_add_br_prop(piface); >> + } >> + piface->pbr_prop->STP = binfo.stp_enabled; >> + >> + ret = 1; >> + >> + out: >> + return ret; >> +} >> + >> +static int list_bridges(EthIfacesList *plist) >> +{ >> + int if_indexes[BR_NUM_MAX]; >> + unsigned long args[3]; >> + int brnum; >> + int i, ret = ERR_LIBBR; >> + EthIface tface; >> + >> + eth_iface_init(&tface); >> + SAFE_CALLOC(tface.name, NAME_BUFF_SIZE, 1); > > free? > >> + >> + args[0] = BRCTL_GET_BRIDGES; >> + args[1] = (unsigned long)if_indexes; >> + args[2] = BR_NUM_MAX; >> + memset(if_indexes, 0, sizeof(if_indexes)); >> + >> + if (0> try_socket_init()) { > > convention > >> + CU_DEBUG("failed to init socket for bridge ioctl," >> + " errno is %d, reason: %s.", >> + errno, strerror(errno)); >> + goto out; >> + } >> + >> + brnum = ioctl(socket_br, SIOCGIFBR, args); >> + if (brnum< 0) { >> + CU_DEBUG("failed tp get bridge, errno is %d, reason: %s.", >> + errno, strerror(errno)); >> + goto out; >> + } >> + >> + i = 0; >> + while (i< brnum) { >> + if (!if_indextoname(if_indexes[i], tface.name)) { >> + CU_DEBUG("failed to translate index %d, errno is %d, >> reason: %s.", >> + if_indexes[i], errno, strerror(errno)); >> + goto out; >> + } >> + >> + ret = get_bridge_info(&tface); >> + if (ret != 1) { >> + CU_DEBUG("failed to get info for %s.", tface.name); >> + continue; >> + } >> + >> + ret = get_bridge_ports(&tface); >> + if (ret != 1) { >> + CU_DEBUG("failed to get info for %s.", tface.name); >> + continue; >> + } >> + >> + if (1 != eth_ifaceslist_add(plist,&tface)) { > > convention > >> + CU_DEBUG("failed to add device to list."); >> + goto out; >> + } >> + eth_iface_uninit(&tface); >> + eth_iface_init(&tface); >> + SAFE_CALLOC(tface.name, NAME_BUFF_SIZE, 1); > > free? > >> + i++; >> + } >> + ret = 1; >> + >> + out: >> + eth_iface_uninit(&tface); >> + try_socket_close(); >> + return ret; >> + >> +} >> + >> +int get_host_eth_ifaces_osapi_bridge(EthIfacesList *plist) >> +{ >> + return list_bridges(plist); >> +} >> diff --git a/libnetwork/host_network_implement_bridge.h b/ >> libnetwork/host_network_implement_bridge.h >> new file mode 100644 >> index 0000000..ed77195 >> --- /dev/null >> +++ b/libnetwork/host_network_implement_bridge.h >> @@ -0,0 +1,8 @@ >> +#ifndef HOST_NETWORK_IMPLE_BRIDGE_H >> +#define HOST_NETWORK_IMPLE_BRIDGE_H >> + >> +#include "host_network_basic.h" >> + >> +int get_host_eth_ifaces_osapi_bridge(EthIfacesList *plist); >> + >> +#endif >> -- >> 1.7.1 >> >> >> _______________________________________________ >> Libvirt-cim mailing list >> Libvirt-cim at redhat.com >> https://www.redhat.com/mailman/listinfo/libvirt-cim >> > > _______________________________________________ > Libvirt-cim mailing list > Libvirt-cim at redhat.com > https://www.redhat.com/mailman/listinfo/libvirt-cim > -- Best Regards Wayne Xia mail:xiawenc at linux.vnet.ibm.com tel:86-010-82450803 From eblima at linux.vnet.ibm.com Fri Jan 20 15:51:04 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 20 Jan 2012 13:51:04 -0200 Subject: [Libvirt-cim] [PATCH v3 0/4] Fix errors raised by Coverity tool In-Reply-To: References: <1326902772-18178-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F198D68.3060907@linux.vnet.ibm.com> Thanks, it would be nice to have this upstream soon so we still have a chance to get it into RHEL 6.3. Best regards, Etrunko On 01/18/2012 06:46 PM, Sharad Mishra wrote: > +1 > > Sharad Mishra > Open Virtualization > Linux Technology Center > IBM > > libvirt-cim-bounces at redhat.com wrote on 01/18/2012 08:06:08 AM: > >> "Eduardo Lima (Etrunko)" >> Sent by: libvirt-cim-bounces at redhat.com >> >> 01/18/2012 08:06 AM >> >> Please respond to >> List for discussion and development of libvirt CIM > >> >> To >> >> libvirt-cim at redhat.com >> >> cc >> >> "Eduardo Lima \(Etrunko\)" >> >> Subject >> >> [Libvirt-cim] [PATCH v3 0/4] Fix errors raised by Coverity tool >> >> From: "Eduardo Lima (Etrunko)" >> >> Yet another series of patches fixing errors revealed by Coverity >> tool. It would >> be nice if we had a similar setup so we could run the tool on a >> regular basis. I >> started playing with clang a while ago. It also provides a static >> analyser, but >> I could not complete the setup by then. >> >> https://bugzilla.redhat.com/show_bug.cgi?id=750418 >> >> Changes from v2: >> - Revert leak change for libxkutil/xmlgen.c in patch 2 which was causing > a >> double-free crash and correctly fix the leak problem. >> >> Changes from v1: >> - Fix compilation error in Patch 1 >> >> Best regards, Etrunko >> >> -- >> Eduardo de Barros Lima >> Software Engineer, Open Virtualization >> Linux Technology Center - IBM/Brazil >> eblima at br.ibm.com >> >> Eduardo Lima (Etrunko) (4): >> libxkutil: Fix possible NULL dereferences >> Fix possible memory leaks >> xml_parse_test: Fix invalid dereference >> Fix possible use of unitialized variables >> >> libxkutil/cs_util_instance.c | 5 +++++ >> libxkutil/device_parsing.c | 14 +++++++------- >> libxkutil/pool_parsing.c | 5 +++-- >> libxkutil/xml_parse_test.c | 3 +-- >> libxkutil/xmlgen.c | 8 +++++--- >> src/Virt_AppliedFilterList.c | 3 ++- >> src/Virt_Device.c | 20 ++++++++++++++++++++ >> src/Virt_DevicePool.c | 19 ++++++++++++++++++- >> src/Virt_SwitchService.c | 24 +++++++++++++++++++ > +---- >> src/Virt_VirtualSystemManagementService.c | 16 ++++++++-------- >> src/Virt_VirtualSystemSnapshotService.c | 2 +- >> 11 files changed, 90 insertions(+), 29 deletions(-) >> >> -- >> 1.7.7.5 >> >> _______________________________________________ >> Libvirt-cim mailing list >> Libvirt-cim at redhat.com >> https://www.redhat.com/mailman/listinfo/libvirt-cim >> > > _______________________________________________ > Libvirt-cim mailing list > Libvirt-cim at redhat.com > https://www.redhat.com/mailman/listinfo/libvirt-cim > -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Fri Jan 20 18:48:22 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 20 Jan 2012 16:48:22 -0200 Subject: [Libvirt-cim] [PATCH v3 0/2] Implementation of a linked list helper Message-ID: <1327085304-23780-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" This series provides a generic linked list implementation for libxkutil that is based on the one originally developed for the libvirt domain events support recently integrated upstream. As test case I ported the ComputerSystemIndication provider code to use this list implementation. In the near future it will be also used by the event loop that I am currently working on to allow systems with libvirt older than 0.9.0 to make use of the same feature. Other possible use cases would be to port the code of libxkutil/*_parsing* to also use the list implementation instead of static arrays. Changes from v2: - Make list struct private Changes from v1: - Fix version iformation in Makefile.am Eduardo Lima (Etrunko) (2): libxkutil: Linked list helper CSI: Use list helper implementation libxkutil/Makefile.am | 51 ++++++-- libxkutil/list_util.c | 243 +++++++++++++++++++++++++++++++++++ libxkutil/list_util.h | 71 ++++++++++ src/Virt_ComputerSystemIndication.c | 95 ++++---------- 4 files changed, 377 insertions(+), 83 deletions(-) create mode 100644 libxkutil/list_util.c create mode 100644 libxkutil/list_util.h -- 1.7.7.6 From eblima at linux.vnet.ibm.com Fri Jan 20 18:48:24 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 20 Jan 2012 16:48:24 -0200 Subject: [Libvirt-cim] [PATCH 2/2] CSI: Use list helper implementation In-Reply-To: <1327085304-23780-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1327085304-23780-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1327085304-23780-3-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- src/Virt_ComputerSystemIndication.c | 95 ++++++++++------------------------- 1 files changed, 26 insertions(+), 69 deletions(-) diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c index eb1a71c..ed1c48d 100644 --- a/src/Virt_ComputerSystemIndication.c +++ b/src/Virt_ComputerSystemIndication.c @@ -19,6 +19,10 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #include #include @@ -34,11 +38,11 @@ #include #include -#include #include -#include -#include "config.h" +#include +#include +#include #include "Virt_ComputerSystem.h" #include "Virt_ComputerSystemIndication.h" @@ -64,8 +68,6 @@ struct _csi_dom_xml_t { char uuid[VIR_UUID_STRING_BUFLEN]; char *name; char *xml; - csi_dom_xml_t *next; - csi_dom_xml_t *prev; }; typedef struct _csi_thread_data_t csi_thread_data_t; @@ -73,7 +75,7 @@ struct _csi_thread_data_t { CMPI_THREAD_TYPE id; int active_filters; int dom_count; - csi_dom_xml_t *dom_list; + list_t *dom_list; struct ind_args *args; }; @@ -83,15 +85,24 @@ static bool lifecycle_enabled = false; static csi_thread_data_t csi_thread_data[CSI_NUM_PLATFORMS] = {{0}, {0}, {0}}; /* - * Domain list manipulation + * Domain manipulation */ -static void csi_dom_xml_free(csi_dom_xml_t *dom) +static void csi_dom_xml_free(void *data) { + csi_dom_xml_t *dom = (csi_dom_xml_t *) data; free(dom->xml); free(dom->name); free(dom); } +static int csi_dom_xml_cmp(void *data, void *cmp_cb_data) +{ + csi_dom_xml_t *dom = (csi_dom_xml_t *) data; + const char *uuid = (const char *) cmp_cb_data; + + return strcmp(dom->uuid, uuid); +} + static int csi_dom_xml_set(csi_dom_xml_t *dom, virDomainPtr dom_ptr, CMPIStatus *s) { const char *name; @@ -149,65 +160,10 @@ static csi_dom_xml_t *csi_dom_xml_new(virDomainPtr dom_ptr, CMPIStatus *s) static void csi_thread_dom_list_append(csi_thread_data_t *thread, csi_dom_xml_t *dom) { - /* empty list */ - if (thread->dom_list == NULL) { - dom->next = dom->prev = dom; - thread->dom_list = dom; - goto end; - } - - dom->next = thread->dom_list; - dom->prev = thread->dom_list->prev; - - thread->dom_list->prev->next = dom; - thread->dom_list->prev = dom; - - end: - thread->dom_count += 1; -} - -static csi_dom_xml_t *csi_thread_dom_list_find(csi_thread_data_t *thread, - const char *uuid) -{ - csi_dom_xml_t *dom; - if (thread->dom_list == NULL) - return NULL; - - dom = thread->dom_list; - - do { - if (STREQ(dom->uuid, uuid)) - return dom; - - dom = dom->next; - } while (dom != thread->dom_list); + thread->dom_list = list_new(csi_dom_xml_free, csi_dom_xml_cmp); - return NULL; -} - -static void csi_thread_dom_list_remove(csi_thread_data_t *thread, - csi_dom_xml_t *dom) -{ - if (dom->next == dom) { /* Only one node */ - thread->dom_list = NULL; - } else { - if (thread->dom_list == dom) /* First node */ - thread->dom_list = dom->next; - - dom->prev->next = dom->next; - dom->next->prev = dom->prev; - } - - thread->dom_count -= 1; - - csi_dom_xml_free(dom); -} - -static void csi_thread_dom_list_free(csi_thread_data_t *thread) -{ - while(thread->dom_list != NULL) - csi_thread_dom_list_remove(thread, thread->dom_list); + list_append(thread->dom_list, dom); } static void csi_free_thread_data(void *data) @@ -217,7 +173,8 @@ static void csi_free_thread_data(void *data) if (data == NULL) return; - csi_thread_dom_list_free(thread); + list_free(thread->dom_list); + thread->dom_list = NULL; stdi_free_ind_args(&thread->args); } @@ -511,7 +468,7 @@ static int update_domain_list(virConnectPtr conn, csi_thread_data_t *thread) CMPIStatus s = {CMPI_RC_OK, NULL}; int i, count; - csi_thread_dom_list_free(thread); + list_free(thread->dom_list); count = get_domain_list(conn, &dom_ptr_list); @@ -573,7 +530,7 @@ static int csi_domain_event_cb(virConnectPtr conn, if (cs_event != CS_CREATED) { char uuid[VIR_UUID_STRING_BUFLEN] = {0}; virDomainGetUUIDString(dom, &uuid[0]); - dom_xml = csi_thread_dom_list_find(thread, uuid); + dom_xml = list_find(thread->dom_list, uuid); } if (dom_xml == NULL) { @@ -594,7 +551,7 @@ static int csi_domain_event_cb(virConnectPtr conn, } } else if (event == VIR_DOMAIN_EVENT_DEFINED && detail == VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) { - csi_thread_dom_list_remove(thread, dom_xml); + list_remove(thread->dom_list, dom_xml); } end: -- 1.7.7.6 From eblima at linux.vnet.ibm.com Fri Jan 20 18:48:23 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 20 Jan 2012 16:48:23 -0200 Subject: [Libvirt-cim] [PATCH 1/2] libxkutil: Linked list helper In-Reply-To: <1327085304-23780-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1327085304-23780-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1327085304-23780-2-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/Makefile.am | 51 ++++++++--- libxkutil/list_util.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++++ libxkutil/list_util.h | 71 ++++++++++++++ 3 files changed, 351 insertions(+), 14 deletions(-) create mode 100644 libxkutil/list_util.c create mode 100644 libxkutil/list_util.h diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am index f1adc03..8d436ad 100644 --- a/libxkutil/Makefile.am +++ b/libxkutil/Makefile.am @@ -1,21 +1,44 @@ # Copyright IBM Corp. 2007 +AM_CFLAGS = \ + $(CFLAGS_STRICT) \ + -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" -AM_CFLAGS = $(CFLAGS_STRICT) \ - -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" +noinst_HEADERS = \ + cs_util.h \ + misc_util.h \ + device_parsing.h \ + xmlgen.h \ + infostore.h \ + pool_parsing.h \ + acl_parsing.h \ + list_util.h -noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ - pool_parsing.h acl_parsing.h +lib_LTLIBRARIES = \ + libxkutil.la -lib_LTLIBRARIES = libxkutil.la +libxkutil_la_SOURCES = \ + cs_util_instance.c \ + misc_util.c \ + device_parsing.c \ + xmlgen.c \ + infostore.c \ + pool_parsing.c \ + acl_parsing.c \ + list_util.c -libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ - xmlgen.c infostore.c pool_parsing.c acl_parsing.c -libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ -libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ - @LIBUUID_LIBS@ +libxkutil_la_LDFLAGS = \ + -version-info @VERSION_INFO@ -noinst_PROGRAMS = xml_parse_test +libxkutil_la_LIBADD = \ + @LIBVIRT_LIBS@ \ + @LIBUUID_LIBS@ -xml_parse_test_SOURCES = xml_parse_test.c -xml_parse_test_LDADD = libxkutil.la \ - @LIBVIRT_LIBS@ +noinst_PROGRAMS = \ + xml_parse_test + +xml_parse_test_SOURCES = \ + xml_parse_test.c + +xml_parse_test_LDADD = \ + libxkutil.la \ + @LIBVIRT_LIBS@ diff --git a/libxkutil/list_util.c b/libxkutil/list_util.c new file mode 100644 index 0000000..f811e86 --- /dev/null +++ b/libxkutil/list_util.c @@ -0,0 +1,243 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Eduardo Lima (Etrunko) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "list_util.h" + +struct _list_node_t { + list_node_t *prev; + list_node_t *next; + void *data; +}; + +struct _list_t { + unsigned int count; + list_node_t *head; + list_data_free_cb free_cb; + list_data_cmp_cb cmp_cb; +}; + +list_t *list_new(list_data_free_cb free_cb, list_data_cmp_cb cmp_cb) +{ + list_t *l = calloc(1, sizeof(*l)); + if (l == NULL) + return NULL; + + l->free_cb = free_cb; + l->cmp_cb = cmp_cb; + return l; +} + +void list_free(list_t *list) +{ + list_node_t *n; + + if (list == NULL || list->head == NULL) + return; + + n = list->head; + + do { + if (list->free_cb) + list->free_cb(n->data); + + n = n->next; + free(n->prev); + } while (n != list->head); + + free(list); +} + +void list_append(list_t *list, void *data) +{ + list_node_t *n; + + if (list == NULL) + return; + + n = calloc(1, sizeof(*n)); + + if (n == NULL) + return; + + n->data = data; + + if (list->head == NULL) { /* empty list */ + n->next = n->prev = n; + list->head = n; + goto end; + } + + n->next = list->head; + n->prev = list->head->prev; + + list->head->prev->next = n; + list->head->prev = n; + + end: + list->count += 1; +} + +void list_prepend(list_t *list, void *data) +{ + list_append(list, data); + list->head = list->head->prev; +} + +void *list_find(list_t *list, void *user_data) +{ + list_node_t *n = list_find_node(list, user_data); + return list_node_data_get(n); +} + +list_node_t *list_find_node(list_t *list, void *user_data) +{ + list_node_t *n; + + if (list == NULL || list->head == NULL || list->cmp_cb == NULL) + return NULL; + + n = list->head; + do { + if (list->cmp_cb(n->data, user_data) == 0) + return n; + + n = n->next; + } while (n != list->head); + + return NULL; +} + +void list_remove(list_t *list, void *data) +{ + list_node_t *n = list_find_node(list, data); + list_remove_node(list, n); +} + +void list_remove_node(list_t *list, list_node_t *node) +{ + if (list == NULL || list->head == NULL || node == NULL) + return; + + if (node->next == node) { /* only 1 item */ + list->head = NULL; + } else { + if (node == list->head) /* first node */ + list->head = node->next; + + node->prev->next = node->next; + node->next->prev = node->prev; + } + + if (list->free_cb) + list->free_cb(node->data); + + free(node); + list->count -= 1; +} + +void list_foreach(list_t *list, list_foreach_cb cb, void *user_data) +{ + list_node_t *node; + + if (list == NULL || list->head == NULL) + return; + + node = list->head; + do { + cb(node->data, user_data); + node = node->next; + } while (node != list->head); +} + +unsigned int list_count(list_t *list) +{ + return list->count; +} + +void *list_node_data_get(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->data; +} + +void list_node_data_set(list_node_t *node, void *data) +{ + if (node == NULL) + return; + + node->data = data; +} + +void *list_first(list_t *list) +{ + return list_node_data_get(list->head); +} + +list_node_t *list_first_node(list_t *list) +{ + return list->head; +} + +void *list_last(list_t *list) +{ + return list_node_data_get(list_last_node(list)); +} + +list_node_t *list_last_node(list_t *list) +{ + if (list == NULL) + return NULL; + + return list->head->prev; +} + +void *list_node_next(list_node_t *node) +{ + return list_node_data_get(list_node_next_node(node)); +} + +list_node_t *list_node_next_node(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->next; +} + +void *list_node_prev(list_node_t *node) +{ + return list_node_data_get(list_node_prev_node(node)); +} + +list_node_t *list_node_prev_node(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->prev; +} diff --git a/libxkutil/list_util.h b/libxkutil/list_util.h new file mode 100644 index 0000000..1bcf1dd --- /dev/null +++ b/libxkutil/list_util.h @@ -0,0 +1,71 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Eduardo Lima (Etrunko) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LIST_UTIL_H +#define __LIST_UTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*list_data_free_cb)(void *data); +typedef int (*list_data_cmp_cb)(void *list_data, void *user_data); +typedef void (*list_foreach_cb)(void *list_data, void *user_data); + +typedef struct _list_node_t list_node_t; +typedef struct _list_t list_t; + +list_t *list_new(list_data_free_cb free_cb, list_data_cmp_cb cmp_cb); +void list_free(list_t *list); + +void list_append(list_t *list, void *data); +void list_prepend(list_t *list, void *data); + +void *list_find(list_t *list, void *user_data); +list_node_t *list_find_node(list_t *list, void *user_data); + +void list_remove(list_t *list, void *data); +void list_remove_node(list_t *list, list_node_t *node); + +void list_foreach(list_t *list, list_foreach_cb cb, void *user_data); + +inline unsigned int list_count(list_t *list); + +inline void *list_node_data_get(list_node_t *node); +inline void list_node_data_set(list_node_t *node, void *data); + +inline void *list_first(list_t *list); +inline list_node_t *list_first_node(list_t *list); + +inline void *list_last(list_t *list); +inline list_node_t *list_last_node(list_t *list); + +inline void *list_node_next(list_node_t *node); +inline list_node_t *list_node_next_node(list_node_t *node); + +inline void *list_node_prev(list_node_t *node); +inline list_node_t *list_node_prev_node(list_node_t *node); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __LIST_UTIL_H */ -- 1.7.7.6 From cvincent at linux.vnet.ibm.com Sun Jan 22 16:37:59 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Sun, 22 Jan 2012 11:37:59 -0500 Subject: [Libvirt-cim] [PATCH] [TEST] Update revision and changeset info In-Reply-To: <1326819705-31213-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326819705-31213-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F1C3B67.1010406@linux.vnet.ibm.com> +1 & pushed. On 01/17/2012 12:01 PM, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > We are now using git (yay!!). Port the commands from mercurial to the git > equivalents. > > Signed-off-by: Eduardo Lima (Etrunko) > --- > suites/libvirt-cim/lib/XenKvmLib/reporting.py | 6 ++---- > 1 files changed, 2 insertions(+), 4 deletions(-) > > diff --git a/suites/libvirt-cim/lib/XenKvmLib/reporting.py b/suites/libvirt-cim/lib/XenKvmLib/reporting.py > index b6df36e..67ec974 100644 > --- a/suites/libvirt-cim/lib/XenKvmLib/reporting.py > +++ b/suites/libvirt-cim/lib/XenKvmLib/reporting.py > @@ -33,10 +33,8 @@ def get_cmd_val(cmd, ip): > return out > > def get_cimtest_version(): > - revision = commands.getoutput("hg parents --template \ > - \"{rev}\" 2>/dev/null") > - changeset = commands.getoutput("hg parents --template \ > - \"{node|short}\" 2>/dev/null") > + revision = commands.getoutput("git rev-list --count HEAD 2>/dev/null") > + changeset = commands.getoutput("git rev-parse --short HEAD 2> /dev/null") > return revision, changeset > > def get_libvirt_ver(ip): -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From cvincent at linux.vnet.ibm.com Sun Jan 22 16:48:58 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Sun, 22 Jan 2012 11:48:58 -0500 Subject: [Libvirt-cim] [PATCH] [TEST] Add .gitignore In-Reply-To: <1326819797-31378-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1326819797-31378-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F1C3DFA.6000300@linux.vnet.ibm.com> +1 & pushed. On 01/17/2012 12:03 PM, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > Signed-off-by: Eduardo Lima (Etrunko) > --- > .gitignore | 4 ++++ > 1 files changed, 4 insertions(+), 0 deletions(-) > create mode 100644 .gitignore > > diff --git a/.gitignore b/.gitignore > new file mode 100644 > index 0000000..cf5ec57 > --- /dev/null > +++ b/.gitignore > @@ -0,0 +1,4 @@ > +*.log > +*.pyc > +*.pyo > +run_report.txt -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From cvincent at linux.vnet.ibm.com Sun Jan 22 16:49:56 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Sun, 22 Jan 2012 11:49:56 -0500 Subject: [Libvirt-cim] [PATCH v2] autoconfiscate.sh: Use proper command for revision count In-Reply-To: <4F170F94.2030809@linux.vnet.ibm.com> References: <1326904329-7730-1-git-send-email-eblima@linux.vnet.ibm.com> <4F170F94.2030809@linux.vnet.ibm.com> Message-ID: <4F1C3E34.7050505@linux.vnet.ibm.com> Pushed On 01/18/2012 01:29 PM, Chip Vincent wrote: > +1 > > $ cat .revision > 1180 > > > On 01/18/2012 11:32 AM, Eduardo Lima (Etrunko) wrote: >> From: "Eduardo Lima (Etrunko)" >> >> Signed-off-by: Eduardo Lima (Etrunko) >> --- >> autoconfiscate.sh | 2 +- >> 1 files changed, 1 insertions(+), 1 deletions(-) >> >> diff --git a/autoconfiscate.sh b/autoconfiscate.sh >> index 8ea8a30..6bdd90a 100755 >> --- a/autoconfiscate.sh >> +++ b/autoconfiscate.sh >> @@ -19,7 +19,7 @@ autoconf --force&& >> >> if test -x $(which git); then >> git rev-parse --short HEAD> .changeset >> - git log | grep "^commit" | wc -l> .revision >> + git rev-list HEAD | wc -l> .revision >> else >> echo "Unknown"> .changeset >> echo "0"> .revision > > -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From xiaxia347work at 163.com Wed Jan 25 20:04:57 2012 From: xiaxia347work at 163.com (xiaxia347work at 163.com) Date: Thu, 26 Jan 2012 04:04:57 +0800 Subject: [Libvirt-cim] [PATCH v5] vlan extention - add function library for readonly usage Message-ID: <1327521897-17291-1-git-send-email-xiaxia347work@163.com> From: Wenchao Xia This patch contain 1 test program and 1 c file doing xml and structure mapping. It expose some API to translate xml to device structure, in a similar way to code in device_parsing.c. Also some other files are changed to let new code use their internal functions. Type following Command in libxkutil directory: sudo CU_DEBUG=stdout .libs/network_parsing_test could see what it have done. v5: calling libvirt API which employ netcf instead of using libnl. From git log these API are available since 0.9.2, and this patch is tested with libvirt 0.9.4. Signed-off-by: Wenchao Xia --- libxkutil/Makefile.am | 12 +- libxkutil/misc_util.c | 10 +- libxkutil/network_parsing.c | 665 ++++++++++++++++++++++++++++++++++++++ libxkutil/network_parsing.h | 160 +++++++++ libxkutil/network_parsing_test.c | 61 ++++ libxkutil/xmlgen.c | 2 +- libxkutil/xmlgen.h | 2 + 7 files changed, 906 insertions(+), 6 deletions(-) create mode 100644 libxkutil/network_parsing.c create mode 100644 libxkutil/network_parsing.h create mode 100644 libxkutil/network_parsing_test.c diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am index f1adc03..c0e62eb 100644 --- a/libxkutil/Makefile.am +++ b/libxkutil/Makefile.am @@ -4,12 +4,14 @@ AM_CFLAGS = $(CFLAGS_STRICT) \ -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ - pool_parsing.h acl_parsing.h + pool_parsing.h acl_parsing.h \ + network_parsing.h lib_LTLIBRARIES = libxkutil.la libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ - xmlgen.c infostore.c pool_parsing.c acl_parsing.c + xmlgen.c infostore.c pool_parsing.c acl_parsing.c \ + network_parsing.c libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ @LIBUUID_LIBS@ @@ -19,3 +21,9 @@ noinst_PROGRAMS = xml_parse_test xml_parse_test_SOURCES = xml_parse_test.c xml_parse_test_LDADD = libxkutil.la \ @LIBVIRT_LIBS@ + +noinst_PROGRAMS += network_parsing_test + +network_parsing_test_SOURCES = network_parsing_test.c +network_parsing_test_LDADD = libxkutil.la \ + @LIBVIRT_LIBS@ diff --git a/libxkutil/misc_util.c b/libxkutil/misc_util.c index 61893c3..1c18c33 100644 --- a/libxkutil/misc_util.c +++ b/libxkutil/misc_util.c @@ -152,9 +152,13 @@ virConnectPtr connect_by_classname(const CMPIBroker *broker, uri = cn_to_uri(classname); if (!uri) { - cu_statusf(broker, s, - CMPI_RC_ERR_FAILED, - "Unable to generate URI from classname"); + if (broker) { + cu_statusf(broker, s, + CMPI_RC_ERR_FAILED, + "Unable to generate URI from classname"); + } + CU_DEBUG("Unable to generate URI from classname," + " uri is %s.", uri); return NULL; } diff --git a/libxkutil/network_parsing.c b/libxkutil/network_parsing.c new file mode 100644 index 0000000..932000c --- /dev/null +++ b/libxkutil/network_parsing.c @@ -0,0 +1,665 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "misc_util.h" +#include "xmlgen.h" +#include "device_parsing.h" +#include "network_parsing.h" + +#define XML_ERROR "Failed to allocate XML memory" + +static void vlan_prop_print(struct VLAN_Prop *pvlan_prop) +{ + struct VLAN_Prop_8021q *p_8021q; + CMD_DEBUG(1, "--VLAN props: type %d.\n", + pvlan_prop->vlan_type); + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + CMD_DEBUG(1, "----IEEE802.1.Q: id %d, parent %s.\n", + p_8021q->vlan_id, p_8021q->parent); + } +} + +static void br_prop_print(struct BR_Prop *pbr_prop) +{ + int i = 0; + CMD_DEBUG(1, "--Bridge props: stp %d, delay %d, port_num %d.\n", + pbr_prop->STP, pbr_prop->delay, pbr_prop->port_num); + if (pbr_prop->port_names != NULL) { + CMD_DEBUG(1, "----Ports attached: "); + while (i < pbr_prop->port_num) { + CMD_DEBUG(1, " %s,", *(pbr_prop->port_names+i)); + i++; + } + CMD_DEBUG(1, "\n"); + } +} + +void eth_iface_print(struct EthIface *piface) +{ + CMD_DEBUG(1, "Iface device: name %s.\n" + "--Main Props: parent %s, attach to %s, mac %s," + " status %d, boot_mode %d, iface type 0x%x.\n", + piface->name, piface->dep_ifname, piface->attach_bridge, + piface->mac, + piface->run_prop.status, piface->run_prop.boot_mode, piface->eth_type); + if (piface->pbr_prop != NULL) { + br_prop_print(piface->pbr_prop); + } + if (piface->pvlan_prop != NULL) { + vlan_prop_print(piface->pvlan_prop); + } + return; +} + +void eth_ifaceslist_print(struct EthIfacesList *plist) +{ + int i = 0; + CMD_DEBUG(1, "Have %d ifaces in the list:\n", plist->count); + while (i < plist->count) { + CMD_DEBUG(1, "%04d ", i); + eth_iface_print(plist->pifaces[i]); + i++; + } +} + +static void vlan_prop_init(struct VLAN_Prop *pvlan_prop, int vlan_type) +{ + struct VLAN_Prop_8021q *p_8021q; + memset(pvlan_prop, 0, sizeof(struct VLAN_Prop)); + pvlan_prop->vlan_type = vlan_type; + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + p_8021q->vlan_id = NUM_NOT_GOT; + } +} + +static void br_prop_init(struct BR_Prop *pbr_prop) +{ + memset(pbr_prop, 0, sizeof(struct BR_Prop)); + pbr_prop->STP = NUM_NOT_GOT; + pbr_prop->delay = NUM_NOT_GOT; + pbr_prop->port_num = NUM_NOT_GOT; +} + +void eth_iface_init(struct EthIface *piface) +{ + memset(piface, 0, sizeof(struct EthIface)); + piface->eth_type = ETH_TYPE_NOT_GOT; + piface->run_prop.status = NUM_NOT_GOT; + piface->run_prop.boot_mode = BOOT_MODE_NOT_GOT; + return; +} + +void eth_iface_add_br_prop(struct EthIface *piface) +{ + if (piface->pbr_prop != NULL) { + return; + } + SAFE_MALLOC(piface->pbr_prop, sizeof(struct BR_Prop)); + br_prop_init(piface->pbr_prop); +} + +void eth_iface_add_vlan_prop(struct EthIface *piface, int vlan_type) +{ + if (piface->pvlan_prop != NULL) { + return; + } + SAFE_MALLOC(piface->pvlan_prop, sizeof(struct VLAN_Prop)); + vlan_prop_init(piface->pvlan_prop, vlan_type); +} + +static void vlan_prop_uninit(struct VLAN_Prop *pvlan_prop) +{ + struct VLAN_Prop_8021q *p_8021q; + if (pvlan_prop == NULL) { + return; + } + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + SAFE_FREE(p_8021q->parent); + } +} + +static void br_prop_uninit(struct BR_Prop *pbr_prop) +{ + int i; + if (pbr_prop == NULL) { + return; + } + i = 0; + if (pbr_prop->port_names != NULL) { + while (i < pbr_prop->port_num) { + SAFE_FREE(pbr_prop->port_names[i]); + i++; + } + SAFE_FREE(pbr_prop->port_names); + } +} + +void eth_iface_uninit(struct EthIface *piface) +{ + if (piface == NULL) { + return; + } + SAFE_FREE(piface->name); + SAFE_FREE(piface->dep_ifname); + SAFE_FREE(piface->attach_bridge); + SAFE_FREE(piface->mac); + br_prop_uninit(piface->pbr_prop); + SAFE_FREE(piface->pbr_prop); + vlan_prop_uninit(piface->pvlan_prop); + SAFE_FREE(piface->pvlan_prop); + return; +} + +void eth_ifaceslist_init(struct EthIfacesList *plist) +{ + plist->count = 0; +} + +void eth_ifaceslist_uninit(struct EthIfacesList *plist) +{ + struct EthIface **t; + int i; + if (plist->count <= 0) { + return; + } + t = plist->pifaces; + i = 0; + while (i < plist->count) { + if (*t != NULL) { + eth_iface_uninit(*t); + SAFE_FREE(*t); + } + t++; + i++; + } + return; +} + +int eth_ifaceslist_add(struct EthIfacesList *plist, struct EthIface **ppiface) +{ + if (plist->count >= MAX_IFACE_NUM) { + CU_DEBUG("too much device found."); + return 0; + } + plist->pifaces[plist->count] = *ppiface; + *ppiface = NULL; + plist->count++; + return 1; +} + +struct EthIface *eth_ifaceslist_search(struct EthIfacesList *plist, + char *name) +{ + int i = 0; + struct EthIface *piface = NULL; + + while (i < plist->count) { + piface = plist->pifaces[i]; + i++; + if (piface != NULL) { + if (0 == strcmp(piface->name, name)) { + return piface; + } + } + } + return NULL; +} + +/* Dummy function to suppress error message from libxml2 */ +static void swallow_err_msg(void *ctx, const char *msg, ...) +{ + /* do nothing, just swallow the message. */ +} + + +static const char *gen_eth_xmlnode_iface(xmlNodePtr root, + struct EthIface *piface, + struct EthIfacesList *plist, + int bridge_port_flag) +{ + const char *msg = NULL; + xmlNodePtr temp_node1 = NULL, temp_node2 = NULL, temp_node3 = NULL; + char *str, buf[16]; + int i; + struct EthIface *pifaceport; + + if (piface->name == NULL) { + msg = "iface have no name.\n"; + goto out; + } + /* netcfg have no xml for iface attatched to bridge */ + if ((piface->attach_bridge != NULL) && (bridge_port_flag != 1)) { + goto out; + } + + temp_node1 = xmlNewChild(root, NULL, BAD_CAST "interface", NULL); + if (temp_node1 == NULL) { + msg = XML_ERROR; + goto out; + } + xmlNewProp(temp_node1, BAD_CAST "name", BAD_CAST piface->name); + if (piface->eth_type & ETH_TYPE_ETHER_ANY) { + if (piface->eth_type & ETH_TYPE_ETHER_SUB_BRIDGE) { + str = "bridge"; + } else if (piface->eth_type & ETH_TYPE_ETHER_SUB_VLAN) { + str = "vlan"; + } else { + str = "ethernet"; + } + xmlNewProp(temp_node1, BAD_CAST "type", BAD_CAST str); + } + + if ((piface->pvlan_prop != NULL) && + (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q)) { + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "vlan", NULL); + snprintf(buf, sizeof(buf), + "%d", piface->pvlan_prop->props.prop_8021q.vlan_id); + xmlNewProp(temp_node2, BAD_CAST "tag", BAD_CAST buf); + temp_node3 = xmlNewChild(temp_node2, NULL, BAD_CAST "interface", NULL); + xmlNewProp(temp_node3, BAD_CAST "name", + BAD_CAST piface->pvlan_prop->props.prop_8021q.parent); + } + + /* if it is attached to bridge, only above properties could be set */ + if (bridge_port_flag == 1) { + goto out; + } + + if (piface->pbr_prop != NULL) { + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "bridge", NULL); + if (piface->pbr_prop->STP == 1) { + snprintf(buf, sizeof(buf), "on"); + } else { + snprintf(buf, sizeof(buf), "off"); + } + xmlNewProp(temp_node2, BAD_CAST "stp", BAD_CAST buf); + if (piface->pbr_prop->delay >= 0) { + snprintf(buf, sizeof(buf), "%d", piface->pbr_prop->delay); + xmlNewProp(temp_node2, BAD_CAST "delay", BAD_CAST buf); + } + if ((piface->pbr_prop->port_names != NULL) && + (piface->pbr_prop->port_num > 0)) { + for (i = 0; i < piface->pbr_prop->port_num; i++) { + pifaceport = eth_ifaceslist_search(plist, + piface->pbr_prop->port_names[i]); + if (pifaceport == NULL) { + CU_DEBUG("failed to find port %s of bridge %s in list.", + piface->pbr_prop->port_names[i], piface->name); + } else { + gen_eth_xmlnode_iface(temp_node2, pifaceport, plist, 1); + } + } + } + } + + if (piface->run_prop.boot_mode == BOOT_MODE_AUTOSTART) { + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "start", NULL); + xmlNewProp(temp_node2, BAD_CAST "mode", BAD_CAST "onboot"); + } else if (piface->run_prop.boot_mode == BOOT_MODE_NONE) { + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "start", NULL); + xmlNewProp(temp_node2, BAD_CAST "mode", BAD_CAST "none"); + } + if (piface->mac != NULL) { + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "mac", NULL); + xmlNewProp(temp_node2, BAD_CAST "address", BAD_CAST piface->mac); + } + + out: + return msg; +} + +static const char *gen_eth_xmlnode(xmlNodePtr root, + struct EthIfacesList *plist) +{ + const char *msg = NULL; + int i = 0; + struct EthIface *piface = NULL; + + while (i < plist->count) { + piface = plist->pifaces[i]; + i++; + msg = gen_eth_xmlnode_iface(root, piface, plist, 0); + if (msg != NULL) { + goto out; + } + } + + out: + return msg; +} + +const char *EthIfaceListTOXML(char **ppxml, + struct EthIfacesList *plist, + int dump_all_flag) +{ + const char *msg = NULL; + xmlNodePtr root = NULL; + + root = xmlNewNode(NULL, BAD_CAST "tmp"); + if (root == NULL) { + msg = "failed to create root node."; + goto out; + } + msg = gen_eth_xmlnode(root, plist); + if (msg == NULL) { + if (dump_all_flag == 1) { + *ppxml = tree_to_xml(root); + } else { + *ppxml = tree_to_xml(root->children); + } + } + + out: + xmlFreeNode(root); + return msg; +} + +static int parse_eth_xmlnode(struct EthIfacesList *plist, xmlNode *inode, + int status, char *attached) +{ + struct EthIface *piface = NULL; + xmlNode *child1 = NULL, *child2 = NULL; + char *temp = NULL, **ppchar; + + SAFE_MALLOC(piface, sizeof(struct EthIface)); + eth_iface_init(piface); + + piface->name = get_attr_value(inode, "name"); + piface->run_prop.status = status; + if (attached != NULL) { + piface->attach_bridge = strdup(attached); + } + temp = get_attr_value(inode, "type"); + if (temp != NULL) { + if (0 == strcmp(temp, "ethernet")) { + piface->eth_type = ETH_TYPE_ETHER_ANY; + } + if (0 == strcmp(temp, "bridge")) { + piface->eth_type = ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_BRIDGE; + } + if (0 == strcmp(temp, "vlan")) { + piface->eth_type = ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_VLAN; + } + SAFE_FREE(temp); + } + + for (child1 = inode->children; child1 != NULL; child1 = child1->next) { + if (XSTREQ(child1->name, "start")) { + temp = get_attr_value(child1, "mode"); + if (0 == strcmp(temp, "onboot")) { + piface->run_prop.boot_mode = BOOT_MODE_AUTOSTART; + } + if (0 == strcmp(temp, "none")) { + piface->run_prop.boot_mode = BOOT_MODE_NONE; + } + SAFE_FREE(temp); + } + if (XSTREQ(child1->name, "mac")) { + piface->mac = get_attr_value(child1, "address"); + } + if (XSTREQ(child1->name, "bridge")) { + eth_iface_add_br_prop(piface); + temp = get_attr_value(child1, "stp"); + if (0 == strcmp(temp, "on")) { + piface->pbr_prop->STP = 1; + } + if (0 == strcmp(temp, "off")) { + piface->pbr_prop->STP = 0; + } + SAFE_FREE(temp); + temp = get_attr_value(child1, "delay"); + piface->pbr_prop->delay = strtol(temp, NULL, 10); + SAFE_FREE(temp); + } + if (XSTREQ(child1->name, "bridge")) { + eth_iface_add_br_prop(piface); + temp = get_attr_value(child1, "stp"); + if (0 == strcmp(temp, "on")) { + piface->pbr_prop->STP = 1; + } + if (0 == strcmp(temp, "off")) { + piface->pbr_prop->STP = 0; + } + SAFE_FREE(temp); + temp = get_attr_value(child1, "delay"); + piface->pbr_prop->delay = strtol(temp, NULL, 10); + SAFE_FREE(temp); + for (child2 = child1->children; child2 != NULL; + child2 = child2->next) { + if (XSTREQ(child2->name, "interface")) { + if (piface->pbr_prop->port_names == NULL) { + SAFE_CALLOC(piface->pbr_prop->port_names, + MAX_IFACE_NUM, sizeof(char *)); + piface->pbr_prop->port_num = 0; + } + ppchar = piface->pbr_prop->port_names + + (piface->pbr_prop->port_num)++; + *ppchar = get_attr_value(child2, "name"); + parse_eth_xmlnode(plist, child2, status, piface->name); + } + } + } + if (XSTREQ(child1->name, "vlan")) { + eth_iface_add_vlan_prop(piface, VLAN_TYPE_802_1_Q); + temp = get_attr_value(child1, "tag"); + piface->pvlan_prop->props.prop_8021q.vlan_id = + strtol(temp, NULL, 10); + SAFE_FREE(temp); + for (child2 = child1->children; child2 != NULL; + child2 = child2->next) { + if (XSTREQ(child2->name, "interface")) { + piface->pvlan_prop->props.prop_8021q.parent = + get_attr_value(child2, "name"); + piface->dep_ifname = + get_attr_value(child2, "name"); + } + } + } + } + + eth_ifaceslist_add(plist, &piface); + return 1; +} + +static const char *XMLToEthIfaceList(struct EthIfacesList *plist, + const char *xml, + int status) +{ + xmlDoc *xmldoc; + xmlXPathContext *xpathCtx; + xmlXPathObject *xpathObj; + xmlChar *xpathstr; + xmlNode **dev_nodes = NULL; + xmlNodeSet *nsv = NULL; + int count = 0; + int len, devidx; + const char *msg = NULL; + + len = strlen(xml) + 1; + xpathstr = (xmlChar *)"/interface"; + + xmlSetGenericErrorFunc(NULL, swallow_err_msg); + if ((xmldoc = xmlParseMemory(xml, len)) == NULL) { + msg = "failed to get xmldoc."; + goto err1; + } + + if ((xpathCtx = xmlXPathNewContext(xmldoc)) == NULL) { + msg = "failed to get pathCtx"; + goto err2; + } + + if ((xpathObj = xmlXPathEvalExpression(xpathstr, xpathCtx)) + == NULL) { + msg = "failed to get xpathObj"; + goto err3; + } + + nsv = xpathObj->nodesetval; + if (nsv == NULL) { + msg = "failed to get nodesetval."; + goto out; + } + + dev_nodes = nsv->nodeTab; + count = nsv->nodeNr; + + if (count <= 0) { + msg = "nodesetval have less that 1 values."; + goto out; + } + + for (devidx = 0; devidx < count; devidx++) { + parse_eth_xmlnode(plist, dev_nodes[devidx], status, NULL); + } + + out: + xmlSetGenericErrorFunc(NULL, NULL); + xmlXPathFreeObject(xpathObj); + + err3: + xmlXPathFreeContext(xpathCtx); + err2: + xmlFreeDoc(xmldoc); + err1: + return msg; +} + +CMPIStatus get_host_ifaces(struct EthIfacesList *plist, + const CMPIBroker *broker, char *prefix) +{ + virConnectPtr conn = NULL; + virInterfacePtr iface; + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; + int num, listnum, i; + char **names = NULL; + char *dump = NULL; + int flags = 0; + const char *msg; + + conn = connect_by_classname(broker, prefix, &s); + if (conn == NULL) { + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, "connect failed."); + goto out; + } + + /* list defined interfaces*/ + num = virConnectNumOfDefinedInterfaces(conn); + if (num < 0) { + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, + "failed to find number of defined interfaces."); + goto out; + } + names = malloc(num * sizeof(char *)); + listnum = virConnectListDefinedInterfaces(conn, names, num); + if (listnum < 0) { + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, + "failed to list names of defined interfaces."); + goto out; + } + CU_DEBUG("%d defined ifaces found from libvirt API.\n", listnum); + + flags |= VIR_INTERFACE_XML_INACTIVE; + for (i = 0; i < listnum; i++) { + iface = virInterfaceLookupByName(conn, names[i]); + if (!iface) { + CU_DEBUG("failed to look up %s.\n", names[i]); + SAFE_FREE(names[i]); + continue; + } + SAFE_FREE(names[i]); + dump = virInterfaceGetXMLDesc(iface, flags); + CU_DEBUG("defined interface %d xml:\n%s", i, dump); + msg = XMLToEthIfaceList(plist, dump, 0); + if (msg != NULL) { + CU_DEBUG("failed parsing eth xml, msg is: %s.", msg); + } + SAFE_FREE(dump); + virInterfaceFree(iface); + } + SAFE_FREE(names); + + /* list active interfaces*/ + num = virConnectNumOfInterfaces(conn); + if (num < 0) { + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, + "failed to find number of active interfaces."); + goto out; + } + names = malloc(num * sizeof(char *)); + + listnum = virConnectListInterfaces(conn, names, num); + if (listnum < 0) { + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, + "failed to list names of active interfacess."); + goto out; + } + CU_DEBUG("%d active ifaces found from libvirt API.\n", listnum); + + flags |= VIR_INTERFACE_XML_INACTIVE; + for (i = 0; i < listnum; i++) { + iface = virInterfaceLookupByName(conn, names[i]); + if (!iface) { + CU_DEBUG("failed to look up %s.\n", names[i]); + SAFE_FREE(names[i]); + continue; + } + SAFE_FREE(names[i]); + dump = virInterfaceGetXMLDesc(iface, flags); + CU_DEBUG("active interface %d xml:\n%s", i, dump); + msg = XMLToEthIfaceList(plist, dump, 1); + if (msg != NULL) { + CU_DEBUG("failed parsing eth xml, msg is: %s.", msg); + } + SAFE_FREE(dump); + virInterfaceFree(iface); + } + s.rc = CMPI_RC_OK; + + out: + virConnectClose(conn); + SAFE_FREE(names); + return s; +} +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/libxkutil/network_parsing.h b/libxkutil/network_parsing.h new file mode 100644 index 0000000..bbfe729 --- /dev/null +++ b/libxkutil/network_parsing.h @@ -0,0 +1,160 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#ifndef NETWORK_PARSING_H +#define NETWORK_PARSING_H + +#include +#include +#include + +/* value defines */ +#define MAX_IFACE_NUM 4096 + +#define NUM_NOT_GOT -1 + +#define ETH_TYPE_BASE_MASK 0xff00 +#define ETH_TYPE_SUB_MASK 0x00ff + +#define CMD_DEBUG_LEVEL 2 + +/* macro functions */ +#define CMD_DEBUG(lvl, fmt, args...) do { \ + if (CMD_DEBUG_LEVEL && (lvl) <= CMD_DEBUG_LEVEL) { \ + debug_print(fmt, ##args); \ + } \ +} while (0) + +#define SAFE_MALLOC(p, size) \ +{ \ + (p) = malloc((size)); \ + if ((p) == NULL) { \ + CU_DEBUG("malloc failed."); \ + } \ +} + +#define SAFE_CALLOC(p, nmen, size) \ +{ \ + (p) = calloc((nmen), (size)); \ + if ((p) == NULL) { \ + CU_DEBUG("calloc failed."); \ + } \ +} + +#define SAFE_FREE(p) {free(p); (p) = NULL; } + +#define RECORD_MSG(broker, ps, rc, fmt, args...) do { \ + CU_DEBUG(fmt, ##args); \ + if (broker) { \ + cu_statusf((broker), (ps), (rc), fmt, ##args); \ + } \ +} while (0) + +typedef enum { + ETH_TYPE_NOT_GOT = 0x0000, + ETH_TYPE_ETHER_ANY = 0x0100, + ETH_TYPE_ETHER_SUB_PHYSICAL = 0x0001, + ETH_TYPE_ETHER_SUB_BRIDGE = 0x0002, + ETH_TYPE_ETHER_SUB_VLAN = 0x0004 +} EthType; + +typedef enum { + VLAN_TYPE_NOT_GOT = NUM_NOT_GOT, + VLAN_TYPE_802_1_Q = 1, + VLAN_TYPE_802_1_QBG = 2, + VLAN_TYPE_802_1_QBH = 4 +} VLANType; + +typedef enum { + BOOT_MODE_NOT_GOT = NUM_NOT_GOT, + BOOT_MODE_AUTOSTART = 1, + BOOT_MODE_NONE = 2 +} BootMode; + +struct BR_Prop { + int STP; + int delay; + char **port_names; + int port_num; +} ; + +struct Run_Prop { + int status; + BootMode boot_mode; +} ; + +struct VLAN_Prop_8021q { + int vlan_id; + char *parent; +} ; + +/* HP vlan standard, TBD */ +struct VLAN_Prop_8021qbg { + int invalid; +} ; + +/* Cisco and VMware vlan standard, TBD */ +struct VLAN_Prop_8021qbh { + int invalid; +} ; + +struct VLAN_Prop { + int vlan_type; + union { + struct VLAN_Prop_8021q prop_8021q; + struct VLAN_Prop_8021qbg prop_8021qbg; + struct VLAN_Prop_8021qbh prop_8021qbh; + } props; +} ; + +/* EthIface is logical devices include eth ports and bridges */ +struct EthIface { + char *name; + char *dep_ifname; /* parent dev name */ + char *attach_bridge; /* bridge the iface is attached to */ + char *mac; + EthType eth_type; + struct Run_Prop run_prop; + /* optional properties */ + struct BR_Prop *pbr_prop; + struct VLAN_Prop *pvlan_prop; +} ; + +struct EthIfacesList { + struct EthIface *pifaces[MAX_IFACE_NUM]; + int count; +} ; + +void eth_iface_init(struct EthIface *piface); +void eth_iface_add_br_prop(struct EthIface *piface); +void eth_iface_add_vlan_prop(struct EthIface *piface, int vlan_type); +void eth_iface_uninit(struct EthIface *piface); + +void eth_ifaceslist_init(struct EthIfacesList *plist); +void eth_ifaceslist_uninit(struct EthIfacesList *plist); +/* ppiface must be allocated from heap, to save code of struct duplication */ +int eth_ifaceslist_add(struct EthIfacesList *plist, struct EthIface **ppiface); +/* returned pointer is direct reference to a member in plist */ +struct EthIface *eth_ifaceslist_search(struct EthIfacesList *plist, + char *name); + +void eth_iface_print(struct EthIface *piface); +void eth_ifaceslist_print(struct EthIfacesList *plist); + +CMPIStatus get_host_ifaces(struct EthIfacesList *plist, + const CMPIBroker *broker, char *prefix); + +const char *EthIfaceListTOXML(char **ppxml, + struct EthIfacesList *plist, + int dump_all_flag); + +#endif diff --git a/libxkutil/network_parsing_test.c b/libxkutil/network_parsing_test.c new file mode 100644 index 0000000..593bfd0 --- /dev/null +++ b/libxkutil/network_parsing_test.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "misc_util.h" +#include "device_parsing.h" +#include "network_parsing.h" + +static const CMPIBroker *broker; + +static long print_and_ret_time_stamp(void) +{ + struct timeval tv; + long ret; + gettimeofday(&tv, NULL); + ret = tv.tv_sec*1000 + tv.tv_usec/1000; + CU_DEBUG("time is [%ld] ms.", ret); + return ret; +} + +/* try retrieve all information, and then map them back to xml. */ +int main(int argc, char **argv) +{ + libvirt_cim_init(); + struct EthIfacesList *plist = NULL; + const char *msg = NULL; + char *genxml = NULL; + CMPIStatus s; + long start_time, end_time; + + SAFE_MALLOC(plist, sizeof(struct EthIfacesList)); + eth_ifaceslist_init(plist); + + start_time = print_and_ret_time_stamp(); + s = get_host_ifaces(plist, broker, "kvm"); + end_time = print_and_ret_time_stamp(); + CU_DEBUG("cost [%d]ms in discovering host network. Result:", + end_time - start_time); + eth_ifaceslist_print(plist); + + msg = EthIfaceListTOXML(&genxml, plist, 1); + CU_DEBUG("xml gen msg is %s. xml is:\n%s", msg, genxml); + SAFE_FREE(genxml); + + eth_ifaceslist_uninit(plist); + SAFE_FREE(plist); + return 0; +} diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index 9a2ada9..001246a 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -830,7 +830,7 @@ static char *features_xml(xmlNodePtr root, struct domain *domain) return NULL; } -static char *tree_to_xml(xmlNodePtr root) +char *tree_to_xml(xmlNodePtr root) { xmlBufferPtr buffer = NULL; xmlSaveCtxtPtr savectx = NULL; diff --git a/libxkutil/xmlgen.h b/libxkutil/xmlgen.h index 743fc82..5d21a94 100644 --- a/libxkutil/xmlgen.h +++ b/libxkutil/xmlgen.h @@ -32,6 +32,8 @@ struct kv { const char *val; }; +char *tree_to_xml(xmlNodePtr root); + char *system_to_xml(struct domain *dominfo); char *device_to_xml(struct virt_device *dev); -- 1.7.1 From cvincent at linux.vnet.ibm.com Wed Jan 25 18:24:56 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Wed, 25 Jan 2012 13:24:56 -0500 Subject: [Libvirt-cim] [PATCH] Fix AppliedFilterList creation and deletion Message-ID: <1327515896-25211-1-git-send-email-cvincent@linux.vnet.ibm.com> From: Chip Vincent Fixes many small issues with the current AppliedFilterList provider. 1) Fix Create to properly return a complete object path and fix Delete to properly parse that path. 2) Persist applied filer rules. Since it's not possible to dyanmically update a single device, I've changed the code to modify and re-define the VM to essentially add/remove ACL filter associations. I also updated the code to minimize domain/device parsing overhead. For some strange reason, our internal APIs sometimes take a virDomainPtr and other times a struct domain * forcing providers who work with domains *and* devices to parse everything twice. Until the internal APIs are cleaned up, I simply parse everything once and then fetch the device manually from the struct domain *. 3) Add VIR_DOMAIN_XML_INACTIVE to virDomainGetXML(). By default, libvirt only returns the XML of the running domain. We need to fetch the *stored* XML that will be used for the next boot so that all changes made while the VM is running are preserved. Signed-off-by: Chip Vincent --- libxkutil/device_parsing.c | 3 +- src/Virt_AppliedFilterList.c | 99 +++++++++++++++++++++++------------------- src/Virt_FilterList.c | 5 ++- 3 files changed, 60 insertions(+), 47 deletions(-) diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c index a1e8d6c..238aa72 100644 --- a/libxkutil/device_parsing.c +++ b/libxkutil/device_parsing.c @@ -996,7 +996,8 @@ int get_devices(virDomainPtr dom, struct virt_device **list, int type) char *xml; int ret; - xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_SECURE); + xml = virDomainGetXMLDesc(dom, + VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); if (xml == NULL) return 0; diff --git a/src/Virt_AppliedFilterList.c b/src/Virt_AppliedFilterList.c index bc31c14..892a90c 100644 --- a/src/Virt_AppliedFilterList.c +++ b/src/Virt_AppliedFilterList.c @@ -97,66 +97,59 @@ static CMPIrc cu_get_ref_path(const CMPIObjectPath *reference, if ((s.rc != CMPI_RC_OK) || CMIsNullValue(value)) return CMPI_RC_ERR_NO_SUCH_PROPERTY; - /* how to parse and object path? */ + if ((value.type != CMPI_ref) || CMIsNullObject(value.value.ref)) + return CMPI_RC_ERR_TYPE_MISMATCH; + + *_reference = value.value.ref; return CMPI_RC_OK; } -/* TODO: Port to libxkutil/device_parsing.c */ -static int update_device(virDomainPtr dom, - struct virt_device *dev) +static int update_domain(virConnectPtr conn, + struct domain *dominfo) { -#if LIBVIR_VERSION_NUMBER > 8000 char *xml = NULL; - int flags = VIR_DOMAIN_DEVICE_MODIFY_CURRENT | - VIR_DOMAIN_DEVICE_MODIFY_CONFIG; - int ret = 0; + virDomainPtr dom = NULL; - xml = device_to_xml(dev); + xml = system_to_xml(dominfo); if (xml == NULL) { - CU_DEBUG("Failed to get XML for device '%s'", dev->id); - goto out; + CU_DEBUG("Failed to get XML from domain %s", dominfo->name); + return 1; } - if (virDomainUpdateDeviceFlags(dom, xml, flags) != 0) { - CU_DEBUG("Failed to dynamically update device"); - goto out; + dom = virDomainDefineXML(conn, xml); + if (dom == NULL) { + CU_DEBUG("Failed to update domain %s", dominfo->name); + return 1; } - ret = 1; - out: - free(xml); + virDomainFree(dom); - return ret; -#else return 0; -#endif } -/* TODO: Port to libxkutil/device_parsing.c */ -static int get_device_by_devid(virDomainPtr dom, +static int get_device_by_devid(struct domain *dominfo, const char *devid, - int type, struct virt_device **dev) { - int i, ret = 0; - struct virt_device *devices = NULL; - int count = get_devices(dom, &devices, type); + int i, ret = 1; + struct virt_device *devices = dominfo->dev_net; + int count = dominfo->dev_net_ct; + + if (dev == NULL) + return ret; for (i = 0; i < count; i++) { if (STREQC(devid, devices[i].id)) { CU_DEBUG("Found '%s'", devices[i].id); - *dev = virt_device_dup(&devices[i]); - if (*dev != NULL) - ret = 1; + *dev = &devices[i]; + ret = 0; break; } } - cleanup_virt_devices(&devices, count); - return ret; } @@ -425,6 +418,8 @@ static CMPIStatus CreateInstance( struct virt_device *device = NULL; virConnectPtr conn = NULL; virDomainPtr dom = NULL; + struct domain *dominfo = NULL; + CMPIObjectPath *_reference = NULL; conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s); if (conn == NULL) @@ -487,8 +482,12 @@ static CMPIStatus CreateInstance( goto out; } - get_device_by_devid(dom, net_name, CIM_RES_TYPE_NET, &device); - if (device == NULL) { + if (get_dominfo(dom, &dominfo) == 0) { + CU_DEBUG("Failed to get dominfo"); + goto out; + } + + if (get_device_by_devid(dominfo, net_name, &device) != 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, "Dependent.Name object does not exist"); @@ -502,14 +501,19 @@ static CMPIStatus CreateInstance( device->dev.net.filter_ref = strdup(filter_name); - if (update_device(dom, device) == 0) { + if (update_domain(conn, dominfo) != 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, - "Failed to update device"); + "Failed to update domain"); goto out; } - CMReturnObjectPath(results, reference); + /* create new object path */ + _reference = CMClone(reference, NULL); + CMAddKey(_reference, "Antecedent", (CMPIValue *)&antecedent, CMPI_ref); + CMAddKey(_reference, "Dependent", (CMPIValue *)&dependent, CMPI_ref); + + CMReturnObjectPath(results, _reference); CU_DEBUG("CreateInstance complete"); out: @@ -542,6 +546,7 @@ static CMPIStatus DeleteInstance( struct virt_device *device = NULL; virConnectPtr conn = NULL; virDomainPtr dom = NULL; + struct domain *dominfo = NULL; conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s); if (conn == NULL) @@ -557,7 +562,7 @@ static CMPIStatus DeleteInstance( goto out; } - if (cu_get_str_path(reference, "DeviceID", + if (cu_get_str_path(antecedent, "DeviceID", &device_name) != CMPI_RC_OK) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, @@ -573,7 +578,7 @@ static CMPIStatus DeleteInstance( goto out; } - if (cu_get_str_path(reference, "Name", + if (cu_get_str_path(dependent, "Name", &filter_name) != CMPI_RC_OK) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, @@ -585,7 +590,7 @@ static CMPIStatus DeleteInstance( if (filter == NULL) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, - "Antecedent.Name object does not exist"); + "Dependent.Name object does not exist"); goto out; } @@ -600,11 +605,15 @@ static CMPIStatus DeleteInstance( goto out; } - get_device_by_devid(dom, net_name, CIM_RES_TYPE_NET, &device); - if (device == NULL) { + if (get_dominfo(dom, &dominfo) == 0) { + CU_DEBUG("Failed to get dominfo"); + goto out; + } + + if (get_device_by_devid(dominfo, net_name, &device) != 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, - "Dependent.Name object does not exist"); + "Antedent.Name object does not exist"); goto out; } @@ -613,14 +622,14 @@ static CMPIStatus DeleteInstance( device->dev.net.filter_ref = NULL; } - if (update_device(dom, device) == 0) { + if (update_domain(conn, dominfo) != 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, - "Failed to update device"); + "Failed to update domain"); goto out; } - CU_DEBUG("CreateInstance complete"); + CU_DEBUG("DeleteInstance complete"); out: free(domain_name); diff --git a/src/Virt_FilterList.c b/src/Virt_FilterList.c index 35d18a9..5b1b6e8 100644 --- a/src/Virt_FilterList.c +++ b/src/Virt_FilterList.c @@ -358,7 +358,10 @@ static CMPIStatus DeleteInstance( goto out; } - delete_filter(conn, filter); + if (delete_filter(conn, filter) != 0) { + CU_DEBUG("Failed to delete filter %s", filter->name); + goto out; + } out: cleanup_filters(&filter, 1); -- 1.7.1 From cvincent at linux.vnet.ibm.com Wed Jan 25 23:47:25 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Wed, 25 Jan 2012 18:47:25 -0500 Subject: [Libvirt-cim] [PATCH v5] vlan extention - add function library for readonly usage In-Reply-To: <1327521897-17291-1-git-send-email-xiaxia347work@163.com> References: <1327521897-17291-1-git-send-email-xiaxia347work@163.com> Message-ID: <4F20948D.2040802@linux.vnet.ibm.com> Thank you for the quick turnaround. The patch applied and built with no issues. Overall, I think the patch looks great. See my comments in-line. Test program: NOTE: I had to remove an existing installation of libvirt-cim, use make rpm, and install an rpm with this change to get the test program to work. Otherwise, the problem would link to the wrong version of libxkutil or not properly find it. So, just updating the rpm was the quickest way to test. $ sudo CU_DEBUG=stdout .libs/network_parsing_test .libs/network_parsing_test: symbol lookup error: .libs/network_parsing_test: undefined symbol: eth_ifaceslist_init For reference, I'm using RHEL 6.2. # rpm -qa | grep libvirt libvirt-devel-0.9.4-23.el6_2.1.x86_64 libvirt-0.9.4-23.el6_2.1.x86_64 libvirt-cim-0.6.0-1.el6.x86_64 Here's the output on my system: network_parsing_test.c(30): time is [1327531475773] ms. misc_util.c(168): Connecting to libvirt with uri `qemu:///system' misc_util.c(130): 'readonly' not found in config file, assuming false network_parsing.c(593): 0 defined ifaces found from libvirt API. network_parsing.c(630): 1 active ifaces found from libvirt API. network_parsing.c(642): active interface 0 xml: network_parsing_test.c(30): time is [1327531475831] ms. network_parsing_test.c(51): cost [58]ms in discovering host network. Result: Have 1 ifaces in the list: 0000 Iface device: name lo. --Main Props: parent (null), attach to (null), mac (null), status 1, boot_mode 1, iface type 0x100. network_parsing_test.c(55): xml gen msg is (null). xml is: This matches the output I get with either netcf or virsh. On 01/25/2012 03:04 PM, xiaxia347work at 163.com wrote: > From: Wenchao Xia > > This patch contain 1 test program and 1 c file doing xml and structure > mapping. It expose some API to translate xml to device structure, in a similar > way to code in device_parsing.c. Also some other files are changed to let new > code use their internal functions. Type following Command in libxkutil > directory: > sudo CU_DEBUG=stdout .libs/network_parsing_test > could see what it have done. > > v5: calling libvirt API which employ netcf instead of using libnl. From git log > these API are available since 0.9.2, and this patch is tested with libvirt > 0.9.4. > > Signed-off-by: Wenchao Xia > --- > libxkutil/Makefile.am | 12 +- > libxkutil/misc_util.c | 10 +- > libxkutil/network_parsing.c | 665 ++++++++++++++++++++++++++++++++++++++ > libxkutil/network_parsing.h | 160 +++++++++ > libxkutil/network_parsing_test.c | 61 ++++ > libxkutil/xmlgen.c | 2 +- > libxkutil/xmlgen.h | 2 + > 7 files changed, 906 insertions(+), 6 deletions(-) > create mode 100644 libxkutil/network_parsing.c > create mode 100644 libxkutil/network_parsing.h > create mode 100644 libxkutil/network_parsing_test.c > > diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am > index f1adc03..c0e62eb 100644 > --- a/libxkutil/Makefile.am > +++ b/libxkutil/Makefile.am > @@ -4,12 +4,14 @@ AM_CFLAGS = $(CFLAGS_STRICT) \ > -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" > > noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ > - pool_parsing.h acl_parsing.h > + pool_parsing.h acl_parsing.h \ > + network_parsing.h > > lib_LTLIBRARIES = libxkutil.la > > libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ > - xmlgen.c infostore.c pool_parsing.c acl_parsing.c > + xmlgen.c infostore.c pool_parsing.c acl_parsing.c \ > + network_parsing.c > libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ > libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ > @LIBUUID_LIBS@ > @@ -19,3 +21,9 @@ noinst_PROGRAMS = xml_parse_test > xml_parse_test_SOURCES = xml_parse_test.c > xml_parse_test_LDADD = libxkutil.la \ > @LIBVIRT_LIBS@ > + > +noinst_PROGRAMS += network_parsing_test > + > +network_parsing_test_SOURCES = network_parsing_test.c > +network_parsing_test_LDADD = libxkutil.la \ > + @LIBVIRT_LIBS@ > diff --git a/libxkutil/misc_util.c b/libxkutil/misc_util.c > index 61893c3..1c18c33 100644 > --- a/libxkutil/misc_util.c > +++ b/libxkutil/misc_util.c > @@ -152,9 +152,13 @@ virConnectPtr connect_by_classname(const CMPIBroker *broker, > > uri = cn_to_uri(classname); > if (!uri) { > - cu_statusf(broker, s, > - CMPI_RC_ERR_FAILED, > - "Unable to generate URI from classname"); > + if (broker) { > + cu_statusf(broker, s, > + CMPI_RC_ERR_FAILED, > + "Unable to generate URI from classname"); > + } > + CU_DEBUG("Unable to generate URI from classname," > + " uri is %s.", uri); > return NULL; > } > > diff --git a/libxkutil/network_parsing.c b/libxkutil/network_parsing.c > new file mode 100644 > index 0000000..932000c > --- /dev/null > +++ b/libxkutil/network_parsing.c > @@ -0,0 +1,665 @@ > +/* > + * Copyright IBM Corp. 2012 > + * > + * Authors: > + * Wenchao Xia > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > + */ > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > + > +#include "misc_util.h" > +#include "xmlgen.h" > +#include "device_parsing.h" > +#include "network_parsing.h" > + > +#define XML_ERROR "Failed to allocate XML memory" I see this is dup'd from xmlgen.c. Perhaps we should just move it to xmlgen.h so everyone can share? > + > +static void vlan_prop_print(struct VLAN_Prop *pvlan_prop) > +{ > + struct VLAN_Prop_8021q *p_8021q; > + CMD_DEBUG(1, "--VLAN props: type %d.\n", > + pvlan_prop->vlan_type); > + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { > + p_8021q =&(pvlan_prop->props.prop_8021q); > + CMD_DEBUG(1, "----IEEE802.1.Q: id %d, parent %s.\n", > + p_8021q->vlan_id, p_8021q->parent); > + } > +} > + > +static void br_prop_print(struct BR_Prop *pbr_prop) > +{ > + int i = 0; > + CMD_DEBUG(1, "--Bridge props: stp %d, delay %d, port_num %d.\n", > + pbr_prop->STP, pbr_prop->delay, pbr_prop->port_num); > + if (pbr_prop->port_names != NULL) { > + CMD_DEBUG(1, "----Ports attached: "); > + while (i< pbr_prop->port_num) { > + CMD_DEBUG(1, " %s,", *(pbr_prop->port_names+i)); > + i++; > + } > + CMD_DEBUG(1, "\n"); > + } > +} > + > +void eth_iface_print(struct EthIface *piface) > +{ > + CMD_DEBUG(1, "Iface device: name %s.\n" > + "--Main Props: parent %s, attach to %s, mac %s," > + " status %d, boot_mode %d, iface type 0x%x.\n", > + piface->name, piface->dep_ifname, piface->attach_bridge, > + piface->mac, > + piface->run_prop.status, piface->run_prop.boot_mode, piface->eth_type); > + if (piface->pbr_prop != NULL) { > + br_prop_print(piface->pbr_prop); > + } > + if (piface->pvlan_prop != NULL) { > + vlan_prop_print(piface->pvlan_prop); > + } > + return; > +} > + > +void eth_ifaceslist_print(struct EthIfacesList *plist) > +{ > + int i = 0; > + CMD_DEBUG(1, "Have %d ifaces in the list:\n", plist->count); > + while (i< plist->count) { > + CMD_DEBUG(1, "%04d ", i); > + eth_iface_print(plist->pifaces[i]); > + i++; > + } > +} > + > +static void vlan_prop_init(struct VLAN_Prop *pvlan_prop, int vlan_type) > +{ > + struct VLAN_Prop_8021q *p_8021q; > + memset(pvlan_prop, 0, sizeof(struct VLAN_Prop)); > + pvlan_prop->vlan_type = vlan_type; > + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { > + p_8021q =&(pvlan_prop->props.prop_8021q); > + p_8021q->vlan_id = NUM_NOT_GOT; > + } > +} > + > +static void br_prop_init(struct BR_Prop *pbr_prop) > +{ > + memset(pbr_prop, 0, sizeof(struct BR_Prop)); > + pbr_prop->STP = NUM_NOT_GOT; > + pbr_prop->delay = NUM_NOT_GOT; > + pbr_prop->port_num = NUM_NOT_GOT; > +} > + > +void eth_iface_init(struct EthIface *piface) > +{ > + memset(piface, 0, sizeof(struct EthIface)); > + piface->eth_type = ETH_TYPE_NOT_GOT; > + piface->run_prop.status = NUM_NOT_GOT; > + piface->run_prop.boot_mode = BOOT_MODE_NOT_GOT; > + return; > +} > + > +void eth_iface_add_br_prop(struct EthIface *piface) > +{ > + if (piface->pbr_prop != NULL) { > + return; > + } > + SAFE_MALLOC(piface->pbr_prop, sizeof(struct BR_Prop)); > + br_prop_init(piface->pbr_prop); > +} > + > +void eth_iface_add_vlan_prop(struct EthIface *piface, int vlan_type) > +{ > + if (piface->pvlan_prop != NULL) { > + return; > + } Indent above > + SAFE_MALLOC(piface->pvlan_prop, sizeof(struct VLAN_Prop)); > + vlan_prop_init(piface->pvlan_prop, vlan_type); > +} > + > +static void vlan_prop_uninit(struct VLAN_Prop *pvlan_prop) > +{ > + struct VLAN_Prop_8021q *p_8021q; > + if (pvlan_prop == NULL) { > + return; > + } > + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { > + p_8021q =&(pvlan_prop->props.prop_8021q); > + SAFE_FREE(p_8021q->parent); > + } > +} > + > +static void br_prop_uninit(struct BR_Prop *pbr_prop) > +{ > + int i; > + if (pbr_prop == NULL) { > + return; > + } > + i = 0; why not init i when defined? > + if (pbr_prop->port_names != NULL) { > + while (i< pbr_prop->port_num) { > + SAFE_FREE(pbr_prop->port_names[i]); > + i++; > + } > + SAFE_FREE(pbr_prop->port_names); > + } > +} > + > +void eth_iface_uninit(struct EthIface *piface) > +{ > + if (piface == NULL) { > + return; > + } > + SAFE_FREE(piface->name); > + SAFE_FREE(piface->dep_ifname); > + SAFE_FREE(piface->attach_bridge); > + SAFE_FREE(piface->mac); > + br_prop_uninit(piface->pbr_prop); > + SAFE_FREE(piface->pbr_prop); > + vlan_prop_uninit(piface->pvlan_prop); > + SAFE_FREE(piface->pvlan_prop); > + return; > +} > + > +void eth_ifaceslist_init(struct EthIfacesList *plist) > +{ > + plist->count = 0; > +} > + > +void eth_ifaceslist_uninit(struct EthIfacesList *plist) > +{ > + struct EthIface **t; > + int i; init variable to 0 or NULL > + if (plist->count<= 0) { > + return; > + } > + t = plist->pifaces; > + i = 0; > + while (i< plist->count) { > + if (*t != NULL) { > + eth_iface_uninit(*t); > + SAFE_FREE(*t); > + } > + t++; > + i++; > + } > + return; > +} > + > +int eth_ifaceslist_add(struct EthIfacesList *plist, struct EthIface **ppiface) > +{ > + if (plist->count>= MAX_IFACE_NUM) { > + CU_DEBUG("too much device found."); > + return 0; > + } > + plist->pifaces[plist->count] = *ppiface; > + *ppiface = NULL; > + plist->count++; > + return 1; > +} > + > +struct EthIface *eth_ifaceslist_search(struct EthIfacesList *plist, > + char *name) > +{ > + int i = 0; > + struct EthIface *piface = NULL; > + > + while (i< plist->count) { > + piface = plist->pifaces[i]; > + i++; > + if (piface != NULL) { > + if (0 == strcmp(piface->name, name)) { > + return piface; > + } > + } > + } > + return NULL; > +} > + > +/* Dummy function to suppress error message from libxml2 */ > +static void swallow_err_msg(void *ctx, const char *msg, ...) > +{ > + /* do nothing, just swallow the message. */ > +} > + > + > +static const char *gen_eth_xmlnode_iface(xmlNodePtr root, > + struct EthIface *piface, > + struct EthIfacesList *plist, > + int bridge_port_flag) > +{ > + const char *msg = NULL; > + xmlNodePtr temp_node1 = NULL, temp_node2 = NULL, temp_node3 = NULL; > + char *str, buf[16]; > + int i; > + struct EthIface *pifaceport; By convention, we try to init all pointers. > + > + if (piface->name == NULL) { > + msg = "iface have no name.\n"; > + goto out; > + } > + /* netcfg have no xml for iface attatched to bridge */ s/have/has/ > + if ((piface->attach_bridge != NULL)&& (bridge_port_flag != 1)) { > + goto out; > + } > + > + temp_node1 = xmlNewChild(root, NULL, BAD_CAST "interface", NULL); > + if (temp_node1 == NULL) { > + msg = XML_ERROR; > + goto out; > + } > + xmlNewProp(temp_node1, BAD_CAST "name", BAD_CAST piface->name); > + if (piface->eth_type& ETH_TYPE_ETHER_ANY) { > + if (piface->eth_type& ETH_TYPE_ETHER_SUB_BRIDGE) { > + str = "bridge"; > + } else if (piface->eth_type& ETH_TYPE_ETHER_SUB_VLAN) { > + str = "vlan"; > + } else { > + str = "ethernet"; > + } > + xmlNewProp(temp_node1, BAD_CAST "type", BAD_CAST str); > + } > + > + if ((piface->pvlan_prop != NULL)&& > + (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q)) { > + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "vlan", NULL); > + snprintf(buf, sizeof(buf), > + "%d", piface->pvlan_prop->props.prop_8021q.vlan_id); > + xmlNewProp(temp_node2, BAD_CAST "tag", BAD_CAST buf); > + temp_node3 = xmlNewChild(temp_node2, NULL, BAD_CAST "interface", NULL); > + xmlNewProp(temp_node3, BAD_CAST "name", > + BAD_CAST piface->pvlan_prop->props.prop_8021q.parent); > + } > + > + /* if it is attached to bridge, only above properties could be set */ > + if (bridge_port_flag == 1) { > + goto out; > + } > + > + if (piface->pbr_prop != NULL) { > + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "bridge", NULL); > + if (piface->pbr_prop->STP == 1) { > + snprintf(buf, sizeof(buf), "on"); > + } else { > + snprintf(buf, sizeof(buf), "off"); > + } > + xmlNewProp(temp_node2, BAD_CAST "stp", BAD_CAST buf); > + if (piface->pbr_prop->delay>= 0) { > + snprintf(buf, sizeof(buf), "%d", piface->pbr_prop->delay); > + xmlNewProp(temp_node2, BAD_CAST "delay", BAD_CAST buf); > + } > + if ((piface->pbr_prop->port_names != NULL)&& > + (piface->pbr_prop->port_num> 0)) { > + for (i = 0; i< piface->pbr_prop->port_num; i++) { > + pifaceport = eth_ifaceslist_search(plist, > + piface->pbr_prop->port_names[i]); > + if (pifaceport == NULL) { > + CU_DEBUG("failed to find port %s of bridge %s in list.", > + piface->pbr_prop->port_names[i], piface->name); > + } else { > + gen_eth_xmlnode_iface(temp_node2, pifaceport, plist, 1); > + } > + } > + } > + } > + > + if (piface->run_prop.boot_mode == BOOT_MODE_AUTOSTART) { > + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "start", NULL); > + xmlNewProp(temp_node2, BAD_CAST "mode", BAD_CAST "onboot"); > + } else if (piface->run_prop.boot_mode == BOOT_MODE_NONE) { > + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "start", NULL); > + xmlNewProp(temp_node2, BAD_CAST "mode", BAD_CAST "none"); > + } > + if (piface->mac != NULL) { > + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "mac", NULL); > + xmlNewProp(temp_node2, BAD_CAST "address", BAD_CAST piface->mac); > + } > + > + out: > + return msg; > +} > + > +static const char *gen_eth_xmlnode(xmlNodePtr root, > + struct EthIfacesList *plist) > +{ > + const char *msg = NULL; > + int i = 0; > + struct EthIface *piface = NULL; > + > + while (i< plist->count) { > + piface = plist->pifaces[i]; > + i++; > + msg = gen_eth_xmlnode_iface(root, piface, plist, 0); > + if (msg != NULL) { > + goto out; > + } > + } > + > + out: > + return msg; > +} > + > +const char *EthIfaceListTOXML(char **ppxml, > + struct EthIfacesList *plist, > + int dump_all_flag) > +{ > + const char *msg = NULL; > + xmlNodePtr root = NULL; > + > + root = xmlNewNode(NULL, BAD_CAST "tmp"); > + if (root == NULL) { > + msg = "failed to create root node."; > + goto out; > + } > + msg = gen_eth_xmlnode(root, plist); > + if (msg == NULL) { > + if (dump_all_flag == 1) { > + *ppxml = tree_to_xml(root); > + } else { > + *ppxml = tree_to_xml(root->children); > + } > + } > + > + out: > + xmlFreeNode(root); > + return msg; > +} > + > +static int parse_eth_xmlnode(struct EthIfacesList *plist, xmlNode *inode, > + int status, char *attached) > +{ > + struct EthIface *piface = NULL; > + xmlNode *child1 = NULL, *child2 = NULL; > + char *temp = NULL, **ppchar; > + > + SAFE_MALLOC(piface, sizeof(struct EthIface)); > + eth_iface_init(piface); > + > + piface->name = get_attr_value(inode, "name"); > + piface->run_prop.status = status; > + if (attached != NULL) { > + piface->attach_bridge = strdup(attached); > + } > + temp = get_attr_value(inode, "type"); > + if (temp != NULL) { > + if (0 == strcmp(temp, "ethernet")) { By convention, we compare the function result with a value, in that order. Ex: strcmp(temp, "ethernet") == 0 > + piface->eth_type = ETH_TYPE_ETHER_ANY; > + } > + if (0 == strcmp(temp, "bridge")) { > + piface->eth_type = ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_BRIDGE; > + } > + if (0 == strcmp(temp, "vlan")) { > + piface->eth_type = ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_VLAN; > + } > + SAFE_FREE(temp); > + } > + > + for (child1 = inode->children; child1 != NULL; child1 = child1->next) { > + if (XSTREQ(child1->name, "start")) { > + temp = get_attr_value(child1, "mode"); > + if (0 == strcmp(temp, "onboot")) { > + piface->run_prop.boot_mode = BOOT_MODE_AUTOSTART; > + } > + if (0 == strcmp(temp, "none")) { > + piface->run_prop.boot_mode = BOOT_MODE_NONE; > + } > + SAFE_FREE(temp); > + } > + if (XSTREQ(child1->name, "mac")) { > + piface->mac = get_attr_value(child1, "address"); > + } > + if (XSTREQ(child1->name, "bridge")) { > + eth_iface_add_br_prop(piface); > + temp = get_attr_value(child1, "stp"); > + if (0 == strcmp(temp, "on")) { > + piface->pbr_prop->STP = 1; > + } > + if (0 == strcmp(temp, "off")) { > + piface->pbr_prop->STP = 0; > + } > + SAFE_FREE(temp); > + temp = get_attr_value(child1, "delay"); > + piface->pbr_prop->delay = strtol(temp, NULL, 10); > + SAFE_FREE(temp); > + } > + if (XSTREQ(child1->name, "bridge")) { > + eth_iface_add_br_prop(piface); > + temp = get_attr_value(child1, "stp"); > + if (0 == strcmp(temp, "on")) { > + piface->pbr_prop->STP = 1; > + } > + if (0 == strcmp(temp, "off")) { > + piface->pbr_prop->STP = 0; > + } > + SAFE_FREE(temp); > + temp = get_attr_value(child1, "delay"); > + piface->pbr_prop->delay = strtol(temp, NULL, 10); > + SAFE_FREE(temp); > + for (child2 = child1->children; child2 != NULL; > + child2 = child2->next) { > + if (XSTREQ(child2->name, "interface")) { > + if (piface->pbr_prop->port_names == NULL) { > + SAFE_CALLOC(piface->pbr_prop->port_names, > + MAX_IFACE_NUM, sizeof(char *)); > + piface->pbr_prop->port_num = 0; > + } > + ppchar = piface->pbr_prop->port_names + > + (piface->pbr_prop->port_num)++; > + *ppchar = get_attr_value(child2, "name"); > + parse_eth_xmlnode(plist, child2, status, piface->name); > + } > + } > + } > + if (XSTREQ(child1->name, "vlan")) { > + eth_iface_add_vlan_prop(piface, VLAN_TYPE_802_1_Q); > + temp = get_attr_value(child1, "tag"); > + piface->pvlan_prop->props.prop_8021q.vlan_id = > + strtol(temp, NULL, 10); > + SAFE_FREE(temp); > + for (child2 = child1->children; child2 != NULL; > + child2 = child2->next) { > + if (XSTREQ(child2->name, "interface")) { > + piface->pvlan_prop->props.prop_8021q.parent = > + get_attr_value(child2, "name"); > + piface->dep_ifname = > + get_attr_value(child2, "name"); > + } > + } > + } > + } > + > + eth_ifaceslist_add(plist,&piface); > + return 1; > +} > + > +static const char *XMLToEthIfaceList(struct EthIfacesList *plist, > + const char *xml, > + int status) > +{ > + xmlDoc *xmldoc; > + xmlXPathContext *xpathCtx; > + xmlXPathObject *xpathObj; > + xmlChar *xpathstr; > + xmlNode **dev_nodes = NULL; > + xmlNodeSet *nsv = NULL; > + int count = 0; > + int len, devidx; > + const char *msg = NULL; init everything possible > + > + len = strlen(xml) + 1; > + xpathstr = (xmlChar *)"/interface"; > + > + xmlSetGenericErrorFunc(NULL, swallow_err_msg); > + if ((xmldoc = xmlParseMemory(xml, len)) == NULL) { > + msg = "failed to get xmldoc."; > + goto err1; > + } > + > + if ((xpathCtx = xmlXPathNewContext(xmldoc)) == NULL) { > + msg = "failed to get pathCtx"; > + goto err2; > + } > + > + if ((xpathObj = xmlXPathEvalExpression(xpathstr, xpathCtx)) > + == NULL) { > + msg = "failed to get xpathObj"; > + goto err3; > + } > + > + nsv = xpathObj->nodesetval; > + if (nsv == NULL) { > + msg = "failed to get nodesetval."; > + goto out; > + } > + > + dev_nodes = nsv->nodeTab; > + count = nsv->nodeNr; > + > + if (count<= 0) { > + msg = "nodesetval have less that 1 values."; > + goto out; > + } > + > + for (devidx = 0; devidx< count; devidx++) { > + parse_eth_xmlnode(plist, dev_nodes[devidx], status, NULL); > + } > + > + out: > + xmlSetGenericErrorFunc(NULL, NULL); > + xmlXPathFreeObject(xpathObj); > + > + err3: > + xmlXPathFreeContext(xpathCtx); > + err2: > + xmlFreeDoc(xmldoc); > + err1: > + return msg; > +} > + > +CMPIStatus get_host_ifaces(struct EthIfacesList *plist, > + const CMPIBroker *broker, char *prefix) > +{ > + virConnectPtr conn = NULL; > + virInterfacePtr iface; > + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; > + int num, listnum, i; > + char **names = NULL; > + char *dump = NULL; > + int flags = 0; > + const char *msg; > + > + conn = connect_by_classname(broker, prefix,&s); > + if (conn == NULL) { > + RECORD_MSG(broker,&s, CMPI_RC_ERR_FAILED, "connect failed."); I think there is already a macro for this. CMReturn() and CIMReturnWithString(). See cmpimacs.h. > + goto out; > + } > + > + /* list defined interfaces*/ > + num = virConnectNumOfDefinedInterfaces(conn); > + if (num< 0) { > + RECORD_MSG(broker,&s, CMPI_RC_ERR_FAILED, > + "failed to find number of defined interfaces."); > + goto out; > + } > + names = malloc(num * sizeof(char *)); > + listnum = virConnectListDefinedInterfaces(conn, names, num); > + if (listnum< 0) { > + RECORD_MSG(broker,&s, CMPI_RC_ERR_FAILED, > + "failed to list names of defined interfaces."); > + goto out; > + } > + CU_DEBUG("%d defined ifaces found from libvirt API.\n", listnum); > + > + flags |= VIR_INTERFACE_XML_INACTIVE; Good. We should be fetching the stored XML and not just that of the running VM. > + for (i = 0; i< listnum; i++) { > + iface = virInterfaceLookupByName(conn, names[i]); > + if (!iface) { > + CU_DEBUG("failed to look up %s.\n", names[i]); > + SAFE_FREE(names[i]); > + continue; > + } > + SAFE_FREE(names[i]); > + dump = virInterfaceGetXMLDesc(iface, flags); > + CU_DEBUG("defined interface %d xml:\n%s", i, dump); > + msg = XMLToEthIfaceList(plist, dump, 0); > + if (msg != NULL) { > + CU_DEBUG("failed parsing eth xml, msg is: %s.", msg); > + } > + SAFE_FREE(dump); > + virInterfaceFree(iface); > + } > + SAFE_FREE(names); I recently did some work and avoided using the existing get_devices() internal API to avoid excessive parsing. I'd like to re-factor the existing device parsing APIs to be more re-usable without the overhead. See my second comment in this post https://www.redhat.com/archives/libvirt-cim/2012-January/msg00101.html. > + > + /* list active interfaces*/ > + num = virConnectNumOfInterfaces(conn); > + if (num< 0) { > + RECORD_MSG(broker,&s, CMPI_RC_ERR_FAILED, > + "failed to find number of active interfaces."); > + goto out; > + } > + names = malloc(num * sizeof(char *)); > + > + listnum = virConnectListInterfaces(conn, names, num); > + if (listnum< 0) { > + RECORD_MSG(broker,&s, CMPI_RC_ERR_FAILED, > + "failed to list names of active interfacess."); > + goto out; > + } > + CU_DEBUG("%d active ifaces found from libvirt API.\n", listnum); > + > + flags |= VIR_INTERFACE_XML_INACTIVE; > + for (i = 0; i< listnum; i++) { > + iface = virInterfaceLookupByName(conn, names[i]); > + if (!iface) { > + CU_DEBUG("failed to look up %s.\n", names[i]); > + SAFE_FREE(names[i]); > + continue; > + } > + SAFE_FREE(names[i]); > + dump = virInterfaceGetXMLDesc(iface, flags); Why not rename the dump variable to xml? > + CU_DEBUG("active interface %d xml:\n%s", i, dump); Nit: In general, we've tried to capitalize the first letter of debug message so they are more like normal sentences. IMO, it makes reading logs a tiny bit easier. > + msg = XMLToEthIfaceList(plist, dump, 1); > + if (msg != NULL) { > + CU_DEBUG("failed parsing eth xml, msg is: %s.", msg); > + } > + SAFE_FREE(dump); > + virInterfaceFree(iface); > + } > + s.rc = CMPI_RC_OK; > + > + out: > + virConnectClose(conn); > + SAFE_FREE(names); > + return s; > +} > +/* > + * Local Variables: > + * mode: C > + * c-set-style: "K&R" > + * tab-width: 8 > + * c-basic-offset: 8 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/libxkutil/network_parsing.h b/libxkutil/network_parsing.h > new file mode 100644 > index 0000000..bbfe729 > --- /dev/null > +++ b/libxkutil/network_parsing.h > @@ -0,0 +1,160 @@ > +/* > + * Copyright IBM Corp. 2012 > + * > + * Authors: > + * Wenchao Xia > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + */ > + > +#ifndef NETWORK_PARSING_H > +#define NETWORK_PARSING_H > + > +#include > +#include > +#include > + > +/* value defines */ > +#define MAX_IFACE_NUM 4096 > + > +#define NUM_NOT_GOT -1 > + > +#define ETH_TYPE_BASE_MASK 0xff00 > +#define ETH_TYPE_SUB_MASK 0x00ff > + > +#define CMD_DEBUG_LEVEL 2 > + > +/* macro functions */ > +#define CMD_DEBUG(lvl, fmt, args...) do { \ > + if (CMD_DEBUG_LEVEL&& (lvl)<= CMD_DEBUG_LEVEL) { \ > + debug_print(fmt, ##args); \ > + } \ > +} while (0) I assume this exists to reduce noise in the current libvirt-cim log out put (CU_DEBUG), right? Perhaps should simply extend the current impl and add a CU_DEBUG_LEVEL? For now, I'm okay with this as-is. > + > +#define SAFE_MALLOC(p, size) \ > +{ \ > + (p) = malloc((size)); \ > + if ((p) == NULL) { \ > + CU_DEBUG("malloc failed."); \ > + } \ > +} > + > +#define SAFE_CALLOC(p, nmen, size) \ > +{ \ > + (p) = calloc((nmen), (size)); \ > + if ((p) == NULL) { \ > + CU_DEBUG("calloc failed."); \ > + } \ > +} These are not really 'safe' since the program will likely crash once p is accessed. Rather, they just hide the return code checking. I know it's a lot of code, but I would prefer we put logic like these where the functions are called. Ideally, we'd all move to this sort of approach and handle any abort gracefully. Until, let's keep things simple (and verbose). > + > +#define SAFE_FREE(p) {free(p); (p) = NULL; } > + > +#define RECORD_MSG(broker, ps, rc, fmt, args...) do { \ > + CU_DEBUG(fmt, ##args); \ > + if (broker) { \ > + cu_statusf((broker), (ps), (rc), fmt, ##args); \ > + } \ > +} while (0) Ah, you're macro takes a variable number of args. See virt_set_status is misc_util.h. > + > +typedef enum { > + ETH_TYPE_NOT_GOT = 0x0000, The 'NOT_GOT' is hard to read, IMO. How about just using '_NONE'? > + ETH_TYPE_ETHER_ANY = 0x0100, > + ETH_TYPE_ETHER_SUB_PHYSICAL = 0x0001, > + ETH_TYPE_ETHER_SUB_BRIDGE = 0x0002, > + ETH_TYPE_ETHER_SUB_VLAN = 0x0004 > +} EthType; > + > +typedef enum { > + VLAN_TYPE_NOT_GOT = NUM_NOT_GOT, > + VLAN_TYPE_802_1_Q = 1, > + VLAN_TYPE_802_1_QBG = 2, > + VLAN_TYPE_802_1_QBH = 4 > +} VLANType; > + > +typedef enum { > + BOOT_MODE_NOT_GOT = NUM_NOT_GOT, > + BOOT_MODE_AUTOSTART = 1, > + BOOT_MODE_NONE = 2 > +} BootMode; > + > +struct BR_Prop { > + int STP; > + int delay; > + char **port_names; > + int port_num; > +} ; > + > +struct Run_Prop { > + int status; > + BootMode boot_mode; > +} ; > + > +struct VLAN_Prop_8021q { > + int vlan_id; > + char *parent; > +} ; > + > +/* HP vlan standard, TBD */ > +struct VLAN_Prop_8021qbg { > + int invalid; > +} ; > + > +/* Cisco and VMware vlan standard, TBD */ > +struct VLAN_Prop_8021qbh { > + int invalid; > +} ; > + > +struct VLAN_Prop { > + int vlan_type; > + union { > + struct VLAN_Prop_8021q prop_8021q; > + struct VLAN_Prop_8021qbg prop_8021qbg; > + struct VLAN_Prop_8021qbh prop_8021qbh; > + } props; > +} ; > + > +/* EthIface is logical devices include eth ports and bridges */ > +struct EthIface { > + char *name; > + char *dep_ifname; /* parent dev name */ > + char *attach_bridge; /* bridge the iface is attached to */ > + char *mac; > + EthType eth_type; > + struct Run_Prop run_prop; > + /* optional properties */ > + struct BR_Prop *pbr_prop; > + struct VLAN_Prop *pvlan_prop; > +} ; > + > +struct EthIfacesList { > + struct EthIface *pifaces[MAX_IFACE_NUM]; > + int count; > +} ; > + > +void eth_iface_init(struct EthIface *piface); > +void eth_iface_add_br_prop(struct EthIface *piface); > +void eth_iface_add_vlan_prop(struct EthIface *piface, int vlan_type); > +void eth_iface_uninit(struct EthIface *piface); > + > +void eth_ifaceslist_init(struct EthIfacesList *plist); > +void eth_ifaceslist_uninit(struct EthIfacesList *plist); > +/* ppiface must be allocated from heap, to save code of struct duplication */ > +int eth_ifaceslist_add(struct EthIfacesList *plist, struct EthIface **ppiface); > +/* returned pointer is direct reference to a member in plist */ > +struct EthIface *eth_ifaceslist_search(struct EthIfacesList *plist, > + char *name); > + > +void eth_iface_print(struct EthIface *piface); > +void eth_ifaceslist_print(struct EthIfacesList *plist); > + > +CMPIStatus get_host_ifaces(struct EthIfacesList *plist, > + const CMPIBroker *broker, char *prefix); > + > +const char *EthIfaceListTOXML(char **ppxml, > + struct EthIfacesList *plist, > + int dump_all_flag); > + > +#endif > diff --git a/libxkutil/network_parsing_test.c b/libxkutil/network_parsing_test.c > new file mode 100644 > index 0000000..593bfd0 > --- /dev/null > +++ b/libxkutil/network_parsing_test.c Copyright? > @@ -0,0 +1,61 @@ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > + > +#include "misc_util.h" > +#include "device_parsing.h" > +#include "network_parsing.h" > + > +static const CMPIBroker *broker; > + > +static long print_and_ret_time_stamp(void) > +{ > + struct timeval tv; > + long ret; > + gettimeofday(&tv, NULL); > + ret = tv.tv_sec*1000 + tv.tv_usec/1000; > + CU_DEBUG("time is [%ld] ms.", ret); > + return ret; > +} > + > +/* try retrieve all information, and then map them back to xml. */ > +int main(int argc, char **argv) > +{ > + libvirt_cim_init(); > + struct EthIfacesList *plist = NULL; > + const char *msg = NULL; > + char *genxml = NULL; > + CMPIStatus s; > + long start_time, end_time; > + > + SAFE_MALLOC(plist, sizeof(struct EthIfacesList)); > + eth_ifaceslist_init(plist); > + > + start_time = print_and_ret_time_stamp(); > + s = get_host_ifaces(plist, broker, "kvm"); > + end_time = print_and_ret_time_stamp(); > + CU_DEBUG("cost [%d]ms in discovering host network. Result:", > + end_time - start_time); > + eth_ifaceslist_print(plist); > + > + msg = EthIfaceListTOXML(&genxml, plist, 1); > + CU_DEBUG("xml gen msg is %s. xml is:\n%s", msg, genxml); > + SAFE_FREE(genxml); > + > + eth_ifaceslist_uninit(plist); > + SAFE_FREE(plist); > + return 0; > +} > diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c > index 9a2ada9..001246a 100644 > --- a/libxkutil/xmlgen.c > +++ b/libxkutil/xmlgen.c > @@ -830,7 +830,7 @@ static char *features_xml(xmlNodePtr root, struct domain *domain) > return NULL; > } > > -static char *tree_to_xml(xmlNodePtr root) > +char *tree_to_xml(xmlNodePtr root) > { > xmlBufferPtr buffer = NULL; > xmlSaveCtxtPtr savectx = NULL; > diff --git a/libxkutil/xmlgen.h b/libxkutil/xmlgen.h > index 743fc82..5d21a94 100644 > --- a/libxkutil/xmlgen.h > +++ b/libxkutil/xmlgen.h > @@ -32,6 +32,8 @@ struct kv { > const char *val; > }; > > +char *tree_to_xml(xmlNodePtr root); > + Good re-use! > char *system_to_xml(struct domain *dominfo); > char *device_to_xml(struct virt_device *dev); > -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From cvincent at linux.vnet.ibm.com Wed Jan 25 23:49:00 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Wed, 25 Jan 2012 18:49:00 -0500 Subject: [Libvirt-cim] [PATCH] Plan9fs (aka 9pfs, VirtFS) support for QEMU/KVM environment In-Reply-To: <4EF5082B.4070802@linux.vnet.ibm.com> References: <20111209111656.20645.54429.stgit@deepak-ThinkPad-T60p> <4EF2C4F6.1080206@linux.vnet.ibm.com> <4EF5082B.4070802@linux.vnet.ibm.com> Message-ID: <4F2094EC.6030307@linux.vnet.ibm.com> Gareth: Any thing to add on this? On 12/23/2011 06:00 PM, Chip Vincent wrote: > Deepak, > > Thanks for the patch. I'm waiting to hear back from Gareth and for the 0.6.0 > release to be complete, which is targeted for next week. Assuming this patch > is ack'd, it will be upstream shortly thereafter. > > On 12/22/2011 12:49 AM, Deepak C Shetty wrote: >> On 12/15/2011 11:19 PM, Sharad Mishra wrote: >>> The patch looks good. >>> Gareth is looking if we need to update SettingsDefineCapabilities for >>> template. >>> >>> Regards, >>> Sharad Mishra >>> Open Virtualization >>> Linux Technology Center >>> IBM >>> >> Hi, any outlook on when this patch be merged ? >> Let me know if anything else is needed from my side. >> >> thanx >> deepak >> >> >> _______________________________________________ >> Libvirt-cim mailing list >> Libvirt-cim at redhat.com >> https://www.redhat.com/mailman/listinfo/libvirt-cim > > > -- > Chip Vincent > Open Virtualization > IBM Linux Technology Center > cvincent at linux.vnet.ibm.com > > > _______________________________________________ > Libvirt-cim mailing list > Libvirt-cim at redhat.com > https://www.redhat.com/mailman/listinfo/libvirt-cim -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From eblima at linux.vnet.ibm.com Thu Jan 26 14:03:07 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Thu, 26 Jan 2012 12:03:07 -0200 Subject: [Libvirt-cim] [PATCH] Fix AppliedFilterList creation and deletion In-Reply-To: <1327515896-25211-1-git-send-email-cvincent@linux.vnet.ibm.com> References: <1327515896-25211-1-git-send-email-cvincent@linux.vnet.ibm.com> Message-ID: <4F215D1B.8060205@linux.vnet.ibm.com> On 01/25/2012 04:24 PM, Chip Vincent wrote: > From: Chip Vincent > > Fixes many small issues with the current AppliedFilterList provider. > > 1) Fix Create to properly return a complete object path and fix Delete to > properly parse that path. Nice, I noticed this could be also done for the NestedFilterList instance creation. > > 2) Persist applied filer rules. Since it's not possible to dyanmically update > a single device, I've changed the code to modify and re-define the VM to > essentially add/remove ACL filter associations. > > I also updated the code to minimize domain/device parsing overhead. For > some strange reason, our internal APIs sometimes take a virDomainPtr and > other times a struct domain * forcing providers who work with domains > *and* devices to parse everything twice. Until the internal APIs are > cleaned up, I simply parse everything once and then fetch the device > manually from the struct domain *. > > 3) Add VIR_DOMAIN_XML_INACTIVE to virDomainGetXML(). By default, libvirt only > returns the XML of the running domain. We need to fetch the *stored* XML > that will be used for the next boot so that all changes made while the VM > is running are preserved. > Is this necessary in other places as well?? A grep for virDomainGetXMLDesc in the tree shows some more places where this function is called. > Signed-off-by: Chip Vincent > --- > libxkutil/device_parsing.c | 3 +- > src/Virt_AppliedFilterList.c | 99 +++++++++++++++++++++++------------------- > src/Virt_FilterList.c | 5 ++- > 3 files changed, 60 insertions(+), 47 deletions(-) > > diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c > index a1e8d6c..238aa72 100644 > --- a/libxkutil/device_parsing.c > +++ b/libxkutil/device_parsing.c > @@ -996,7 +996,8 @@ int get_devices(virDomainPtr dom, struct virt_device **list, int type) > char *xml; > int ret; > > - xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_SECURE); > + xml = virDomainGetXMLDesc(dom, > + VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); > if (xml == NULL) > return 0; > Check if this is also necessary in other places where virDomainGetXMLDesc is called, as stated in the comment above. > diff --git a/src/Virt_AppliedFilterList.c b/src/Virt_AppliedFilterList.c > index bc31c14..892a90c 100644 > --- a/src/Virt_AppliedFilterList.c > +++ b/src/Virt_AppliedFilterList.c > @@ -97,66 +97,59 @@ static CMPIrc cu_get_ref_path(const CMPIObjectPath *reference, > if ((s.rc != CMPI_RC_OK) || CMIsNullValue(value)) > return CMPI_RC_ERR_NO_SUCH_PROPERTY; > > - /* how to parse and object path? */ > + if ((value.type != CMPI_ref) || CMIsNullObject(value.value.ref)) > + return CMPI_RC_ERR_TYPE_MISMATCH; > + > + *_reference = value.value.ref; > > return CMPI_RC_OK; > } > > -/* TODO: Port to libxkutil/device_parsing.c */ > -static int update_device(virDomainPtr dom, > - struct virt_device *dev) > +static int update_domain(virConnectPtr conn, > + struct domain *dominfo) > { > -#if LIBVIR_VERSION_NUMBER > 8000 > char *xml = NULL; > - int flags = VIR_DOMAIN_DEVICE_MODIFY_CURRENT | > - VIR_DOMAIN_DEVICE_MODIFY_CONFIG; > - int ret = 0; > + virDomainPtr dom = NULL; > > - xml = device_to_xml(dev); > + xml = system_to_xml(dominfo); > if (xml == NULL) { > - CU_DEBUG("Failed to get XML for device '%s'", dev->id); > - goto out; > + CU_DEBUG("Failed to get XML from domain %s", dominfo->name); > + return 1; > } > > - if (virDomainUpdateDeviceFlags(dom, xml, flags) != 0) { > - CU_DEBUG("Failed to dynamically update device"); > - goto out; > + dom = virDomainDefineXML(conn, xml); > + if (dom == NULL) { > + CU_DEBUG("Failed to update domain %s", dominfo->name); > + return 1; > } > > - ret = 1; > - out: > - free(xml); > + virDomainFree(dom); > Leaking xml. > - return ret; > -#else > return 0; > -#endif > } > > -/* TODO: Port to libxkutil/device_parsing.c */ > -static int get_device_by_devid(virDomainPtr dom, > +static int get_device_by_devid(struct domain *dominfo, > const char *devid, > - int type, > struct virt_device **dev) > { > - int i, ret = 0; > - struct virt_device *devices = NULL; > - int count = get_devices(dom, &devices, type); > + int i, ret = 1; > + struct virt_device *devices = dominfo->dev_net; > + int count = dominfo->dev_net_ct; > + > + if (dev == NULL) > + return ret; > > for (i = 0; i < count; i++) { > if (STREQC(devid, devices[i].id)) { > CU_DEBUG("Found '%s'", devices[i].id); > > - *dev = virt_device_dup(&devices[i]); > - if (*dev != NULL) > - ret = 1; > + *dev = &devices[i]; > + ret = 0; > Just return 0 here instead as you are not doing anything else after the loop. In this case you can also get rid of the variable ret. > break; > } > } > > - cleanup_virt_devices(&devices, count); > - > return ret; > } > > @@ -425,6 +418,8 @@ static CMPIStatus CreateInstance( > struct virt_device *device = NULL; > virConnectPtr conn = NULL; > virDomainPtr dom = NULL; > + struct domain *dominfo = NULL; > + CMPIObjectPath *_reference = NULL; > > conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s); > if (conn == NULL) > @@ -487,8 +482,12 @@ static CMPIStatus CreateInstance( > goto out; > } > > - get_device_by_devid(dom, net_name, CIM_RES_TYPE_NET, &device); > - if (device == NULL) { > + if (get_dominfo(dom, &dominfo) == 0) { > + CU_DEBUG("Failed to get dominfo"); > + goto out; > + } > + > + if (get_device_by_devid(dominfo, net_name, &device) != 0) { > cu_statusf(_BROKER, &s, > CMPI_RC_ERR_FAILED, > "Dependent.Name object does not exist"); > @@ -502,14 +501,19 @@ static CMPIStatus CreateInstance( > > device->dev.net.filter_ref = strdup(filter_name); > > - if (update_device(dom, device) == 0) { > + if (update_domain(conn, dominfo) != 0) { > cu_statusf(_BROKER, &s, > CMPI_RC_ERR_FAILED, > - "Failed to update device"); > + "Failed to update domain"); > goto out; > } > > - CMReturnObjectPath(results, reference); > + /* create new object path */ > + _reference = CMClone(reference, NULL); > + CMAddKey(_reference, "Antecedent", (CMPIValue *)&antecedent, CMPI_ref); > + CMAddKey(_reference, "Dependent", (CMPIValue *)&dependent, CMPI_ref); > + > + CMReturnObjectPath(results, _reference); So this could go to NestedFilterList as well? > CU_DEBUG("CreateInstance complete"); > > out: > @@ -542,6 +546,7 @@ static CMPIStatus DeleteInstance( > struct virt_device *device = NULL; > virConnectPtr conn = NULL; > virDomainPtr dom = NULL; > + struct domain *dominfo = NULL; > > conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s); > if (conn == NULL) > @@ -557,7 +562,7 @@ static CMPIStatus DeleteInstance( > goto out; > } > > - if (cu_get_str_path(reference, "DeviceID", > + if (cu_get_str_path(antecedent, "DeviceID", > &device_name) != CMPI_RC_OK) { > cu_statusf(_BROKER, &s, > CMPI_RC_ERR_FAILED, > @@ -573,7 +578,7 @@ static CMPIStatus DeleteInstance( > goto out; > } > > - if (cu_get_str_path(reference, "Name", > + if (cu_get_str_path(dependent, "Name", > &filter_name) != CMPI_RC_OK) { > cu_statusf(_BROKER, &s, > CMPI_RC_ERR_FAILED, > @@ -585,7 +590,7 @@ static CMPIStatus DeleteInstance( > if (filter == NULL) { > cu_statusf(_BROKER, &s, > CMPI_RC_ERR_FAILED, > - "Antecedent.Name object does not exist"); > + "Dependent.Name object does not exist"); > goto out; > } > > @@ -600,11 +605,15 @@ static CMPIStatus DeleteInstance( > goto out; > } > > - get_device_by_devid(dom, net_name, CIM_RES_TYPE_NET, &device); > - if (device == NULL) { > + if (get_dominfo(dom, &dominfo) == 0) { > + CU_DEBUG("Failed to get dominfo"); > + goto out; > + } > + > + if (get_device_by_devid(dominfo, net_name, &device) != 0) { > cu_statusf(_BROKER, &s, > CMPI_RC_ERR_FAILED, > - "Dependent.Name object does not exist"); > + "Antedent.Name object does not exist"); Spell check. > goto out; > } > > @@ -613,14 +622,14 @@ static CMPIStatus DeleteInstance( > device->dev.net.filter_ref = NULL; > } > > - if (update_device(dom, device) == 0) { > + if (update_domain(conn, dominfo) != 0) { > cu_statusf(_BROKER, &s, > CMPI_RC_ERR_FAILED, > - "Failed to update device"); > + "Failed to update domain"); > goto out; > } > > - CU_DEBUG("CreateInstance complete"); > + CU_DEBUG("DeleteInstance complete"); > > out: > free(domain_name); > diff --git a/src/Virt_FilterList.c b/src/Virt_FilterList.c > index 35d18a9..5b1b6e8 100644 > --- a/src/Virt_FilterList.c > +++ b/src/Virt_FilterList.c > @@ -358,7 +358,10 @@ static CMPIStatus DeleteInstance( > goto out; > } > > - delete_filter(conn, filter); > + if (delete_filter(conn, filter) != 0) { > + CU_DEBUG("Failed to delete filter %s", filter->name); > + goto out; > + } > > out: > cleanup_filters(&filter, 1); -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From cvincent at linux.vnet.ibm.com Thu Jan 26 14:58:21 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Thu, 26 Jan 2012 09:58:21 -0500 Subject: [Libvirt-cim] [PATCH v2] Fix AppliedFilterList creation and deletion Message-ID: <1327589901-28693-1-git-send-email-cvincent@linux.vnet.ibm.com> From: Chip Vincent Fixes many small issues with the current AppliedFilterList provider. 1) Fix Create to properly return a complete object path and fix Delete to properly parse that path. 2) Persist applied filer rules. Since it's not possible to dyanmically update a single device, I've changed the code to modify and re-define the VM to essentially add/remove ACL filter associations. I also updated the code to minimize domain/device parsing overhead. For some strange reason, our internal APIs sometimes take a virDomainPtr and other times a struct domain * forcing providers who work with domains *and* devices to parse everything twice. Until the internal APIs are cleaned up, I simply parse everything once and then fetch the device manually from the struct domain *. 3) Add VIR_DOMAIN_XML_INACTIVE to virDomainGetXML(). By default, libvirt only returns the XML of the running domain. We need to fetch the *stored* XML that will be used for the next boot so that all changes made while the VM is running are preserved. Changes from v1: - Fix leak and other comments - Fix all cases virDomainGetXML() - Fix NestedFilterList Create/Delete instance Signed-off-by: Chip Vincent --- libxkutil/device_parsing.c | 6 ++- src/Virt_AppliedFilterList.c | 97 +++++++++++++++++++---------------- src/Virt_ComputerSystem.c | 3 +- src/Virt_ComputerSystemIndication.c | 3 +- src/Virt_FilterList.c | 5 ++- src/Virt_NestedFilterList.c | 13 ++++- src/Virt_VSMigrationService.c | 3 +- 7 files changed, 78 insertions(+), 52 deletions(-) diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c index a1e8d6c..ff86f2a 100644 --- a/libxkutil/device_parsing.c +++ b/libxkutil/device_parsing.c @@ -996,7 +996,8 @@ int get_devices(virDomainPtr dom, struct virt_device **list, int type) char *xml; int ret; - xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_SECURE); + xml = virDomainGetXMLDesc(dom, + VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); if (xml == NULL) return 0; @@ -1241,7 +1242,8 @@ int get_dominfo(virDomainPtr dom, struct domain **dominfo) char *xml; int ret; int start; - xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_SECURE); + xml = virDomainGetXMLDesc(dom, + VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); if (xml == NULL) return 0; diff --git a/src/Virt_AppliedFilterList.c b/src/Virt_AppliedFilterList.c index bc31c14..538adf4 100644 --- a/src/Virt_AppliedFilterList.c +++ b/src/Virt_AppliedFilterList.c @@ -97,67 +97,60 @@ static CMPIrc cu_get_ref_path(const CMPIObjectPath *reference, if ((s.rc != CMPI_RC_OK) || CMIsNullValue(value)) return CMPI_RC_ERR_NO_SUCH_PROPERTY; - /* how to parse and object path? */ + if ((value.type != CMPI_ref) || CMIsNullObject(value.value.ref)) + return CMPI_RC_ERR_TYPE_MISMATCH; + + *_reference = value.value.ref; return CMPI_RC_OK; } -/* TODO: Port to libxkutil/device_parsing.c */ -static int update_device(virDomainPtr dom, - struct virt_device *dev) +static int update_domain(virConnectPtr conn, + struct domain *dominfo) { -#if LIBVIR_VERSION_NUMBER > 8000 char *xml = NULL; - int flags = VIR_DOMAIN_DEVICE_MODIFY_CURRENT | - VIR_DOMAIN_DEVICE_MODIFY_CONFIG; - int ret = 0; + virDomainPtr dom = NULL; - xml = device_to_xml(dev); + xml = system_to_xml(dominfo); if (xml == NULL) { - CU_DEBUG("Failed to get XML for device '%s'", dev->id); + CU_DEBUG("Failed to get XML from domain %s", dominfo->name); goto out; } - if (virDomainUpdateDeviceFlags(dom, xml, flags) != 0) { - CU_DEBUG("Failed to dynamically update device"); + dom = virDomainDefineXML(conn, xml); + if (dom == NULL) { + CU_DEBUG("Failed to update domain %s", dominfo->name); goto out; } - ret = 1; out: free(xml); + virDomainFree(dom); - return ret; -#else return 0; -#endif } -/* TODO: Port to libxkutil/device_parsing.c */ -static int get_device_by_devid(virDomainPtr dom, +static int get_device_by_devid(struct domain *dominfo, const char *devid, - int type, struct virt_device **dev) { - int i, ret = 0; - struct virt_device *devices = NULL; - int count = get_devices(dom, &devices, type); + int i; + struct virt_device *devices = dominfo->dev_net; + int count = dominfo->dev_net_ct; + + if (dev == NULL) + return 0; for (i = 0; i < count; i++) { if (STREQC(devid, devices[i].id)) { CU_DEBUG("Found '%s'", devices[i].id); - *dev = virt_device_dup(&devices[i]); - if (*dev != NULL) - ret = 1; - - break; + *dev = &devices[i]; + return 0; } } - cleanup_virt_devices(&devices, count); - - return ret; + return 1; } /** @@ -425,6 +418,8 @@ static CMPIStatus CreateInstance( struct virt_device *device = NULL; virConnectPtr conn = NULL; virDomainPtr dom = NULL; + struct domain *dominfo = NULL; + CMPIObjectPath *_reference = NULL; conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s); if (conn == NULL) @@ -487,8 +482,12 @@ static CMPIStatus CreateInstance( goto out; } - get_device_by_devid(dom, net_name, CIM_RES_TYPE_NET, &device); - if (device == NULL) { + if (get_dominfo(dom, &dominfo) == 0) { + CU_DEBUG("Failed to get dominfo"); + goto out; + } + + if (get_device_by_devid(dominfo, net_name, &device) != 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, "Dependent.Name object does not exist"); @@ -502,14 +501,19 @@ static CMPIStatus CreateInstance( device->dev.net.filter_ref = strdup(filter_name); - if (update_device(dom, device) == 0) { + if (update_domain(conn, dominfo) != 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, - "Failed to update device"); + "Failed to update domain"); goto out; } - CMReturnObjectPath(results, reference); + /* create new object path */ + _reference = CMClone(reference, NULL); + CMAddKey(_reference, "Antecedent", (CMPIValue *)&antecedent, CMPI_ref); + CMAddKey(_reference, "Dependent", (CMPIValue *)&dependent, CMPI_ref); + + CMReturnObjectPath(results, _reference); CU_DEBUG("CreateInstance complete"); out: @@ -542,6 +546,7 @@ static CMPIStatus DeleteInstance( struct virt_device *device = NULL; virConnectPtr conn = NULL; virDomainPtr dom = NULL; + struct domain *dominfo = NULL; conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s); if (conn == NULL) @@ -557,7 +562,7 @@ static CMPIStatus DeleteInstance( goto out; } - if (cu_get_str_path(reference, "DeviceID", + if (cu_get_str_path(antecedent, "DeviceID", &device_name) != CMPI_RC_OK) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, @@ -573,7 +578,7 @@ static CMPIStatus DeleteInstance( goto out; } - if (cu_get_str_path(reference, "Name", + if (cu_get_str_path(dependent, "Name", &filter_name) != CMPI_RC_OK) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, @@ -585,7 +590,7 @@ static CMPIStatus DeleteInstance( if (filter == NULL) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, - "Antecedent.Name object does not exist"); + "Dependent.Name object does not exist"); goto out; } @@ -600,11 +605,15 @@ static CMPIStatus DeleteInstance( goto out; } - get_device_by_devid(dom, net_name, CIM_RES_TYPE_NET, &device); - if (device == NULL) { + if (get_dominfo(dom, &dominfo) == 0) { + CU_DEBUG("Failed to get dominfo"); + goto out; + } + + if (get_device_by_devid(dominfo, net_name, &device) != 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, - "Dependent.Name object does not exist"); + "Antecedent.Name object does not exist"); goto out; } @@ -613,14 +622,14 @@ static CMPIStatus DeleteInstance( device->dev.net.filter_ref = NULL; } - if (update_device(dom, device) == 0) { + if (update_domain(conn, dominfo) != 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, - "Failed to update device"); + "Failed to update domain"); goto out; } - CU_DEBUG("CreateInstance complete"); + CU_DEBUG("DeleteInstance complete"); out: free(domain_name); diff --git a/src/Virt_ComputerSystem.c b/src/Virt_ComputerSystem.c index 582253a..e6c7e55 100644 --- a/src/Virt_ComputerSystem.c +++ b/src/Virt_ComputerSystem.c @@ -926,7 +926,8 @@ static CMPIStatus domain_reset(virDomainPtr dom) return s; } - xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_SECURE); + xml = virDomainGetXMLDesc(dom, + VIR_DOMAIN_XML_INACTIVE |VIR_DOMAIN_XML_SECURE); if (xml == NULL) { CU_DEBUG("Unable to retrieve domain XML"); virt_set_status(_BROKER, &s, diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c index eb1a71c..6ef2ddc 100644 --- a/src/Virt_ComputerSystemIndication.c +++ b/src/Virt_ComputerSystemIndication.c @@ -107,7 +107,8 @@ static int csi_dom_xml_set(csi_dom_xml_t *dom, virDomainPtr dom_ptr, CMPIStatus dom->name = strdup(name); /* xml */ - dom->xml = virDomainGetXMLDesc(dom_ptr, VIR_DOMAIN_XML_SECURE); + dom->xml = virDomainGetXMLDesc(dom_ptr, + VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); if (dom->xml == NULL) { cu_statusf(_BROKER, s, CMPI_RC_ERR_FAILED, diff --git a/src/Virt_FilterList.c b/src/Virt_FilterList.c index 35d18a9..5b1b6e8 100644 --- a/src/Virt_FilterList.c +++ b/src/Virt_FilterList.c @@ -358,7 +358,10 @@ static CMPIStatus DeleteInstance( goto out; } - delete_filter(conn, filter); + if (delete_filter(conn, filter) != 0) { + CU_DEBUG("Failed to delete filter %s", filter->name); + goto out; + } out: cleanup_filters(&filter, 1); diff --git a/src/Virt_NestedFilterList.c b/src/Virt_NestedFilterList.c index 894cd7c..b72c582 100644 --- a/src/Virt_NestedFilterList.c +++ b/src/Virt_NestedFilterList.c @@ -98,7 +98,10 @@ static CMPIrc cu_get_ref_path(const CMPIObjectPath *reference, if ((s.rc != CMPI_RC_OK) || CMIsNullValue(value)) return CMPI_RC_ERR_NO_SUCH_PROPERTY; - /* how to parse and object path? */ + if ((value.type != CMPI_ref) || CMIsNullObject(value.value.ref)) + return CMPI_RC_ERR_TYPE_MISMATCH; + + *_reference = value.value.ref; return CMPI_RC_OK; } @@ -305,6 +308,7 @@ static CMPIStatus CreateInstance( const char *child_name = NULL; struct acl_filter *child_filter = NULL; virConnectPtr conn = NULL; + CMPIObjectPath *_reference = NULL; CU_DEBUG("Reference = %s", REF2STR(reference)); @@ -383,6 +387,11 @@ static CMPIStatus CreateInstance( goto out; } + /* create new object path */ + _reference = CMClone(reference, NULL); + CMAddKey(_reference, "Antecedent", (CMPIValue *)&antecedent, CMPI_ref); + CMAddKey(_reference, "Dependent", (CMPIValue *)&dependent, CMPI_ref); + CMReturnObjectPath(results, reference); CU_DEBUG("CreateInstance completed"); @@ -475,7 +484,7 @@ static CMPIStatus DeleteInstance( goto out; } - CU_DEBUG("CreateInstance completed"); + CU_DEBUG("DeleteInstance completed"); out: cleanup_filters(&parent_filter, 1); diff --git a/src/Virt_VSMigrationService.c b/src/Virt_VSMigrationService.c index d393787..76e3d25 100644 --- a/src/Virt_VSMigrationService.c +++ b/src/Virt_VSMigrationService.c @@ -1070,7 +1070,8 @@ static CMPIStatus prepare_migrate(virDomainPtr dom, { CMPIStatus s = {CMPI_RC_OK, NULL}; - *xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_SECURE); + *xml = virDomainGetXMLDesc(dom, + VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); if (*xml == NULL) { virt_set_status(_BROKER, &s, -- 1.7.1 From eblima at linux.vnet.ibm.com Thu Jan 26 16:08:43 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Thu, 26 Jan 2012 14:08:43 -0200 Subject: [Libvirt-cim] [PATCH v2] Fix AppliedFilterList creation and deletion In-Reply-To: <1327589901-28693-1-git-send-email-cvincent@linux.vnet.ibm.com> References: <1327589901-28693-1-git-send-email-cvincent@linux.vnet.ibm.com> Message-ID: <4F217A8B.50504@linux.vnet.ibm.com> On 01/26/2012 12:58 PM, Chip Vincent wrote: > From: Chip Vincent > > Fixes many small issues with the current AppliedFilterList provider. > > 1) Fix Create to properly return a complete object path and fix Delete to > properly parse that path. > > 2) Persist applied filer rules. Since it's not possible to dyanmically update > a single device, I've changed the code to modify and re-define the VM to > essentially add/remove ACL filter associations. > > I also updated the code to minimize domain/device parsing overhead. For > some strange reason, our internal APIs sometimes take a virDomainPtr and > other times a struct domain * forcing providers who work with domains > *and* devices to parse everything twice. Until the internal APIs are > cleaned up, I simply parse everything once and then fetch the device > manually from the struct domain *. > > 3) Add VIR_DOMAIN_XML_INACTIVE to virDomainGetXML(). By default, libvirt only > returns the XML of the running domain. We need to fetch the *stored* XML > that will be used for the next boot so that all changes made while the VM > is running are preserved. > > Changes from v1: > - Fix leak and other comments > - Fix all cases virDomainGetXML() > - Fix NestedFilterList Create/Delete instance Almost there, see below: [snip] > diff --git a/src/Virt_NestedFilterList.c b/src/Virt_NestedFilterList.c > index 894cd7c..b72c582 100644 > --- a/src/Virt_NestedFilterList.c > +++ b/src/Virt_NestedFilterList.c > @@ -98,7 +98,10 @@ static CMPIrc cu_get_ref_path(const CMPIObjectPath *reference, > if ((s.rc != CMPI_RC_OK) || CMIsNullValue(value)) > return CMPI_RC_ERR_NO_SUCH_PROPERTY; > > - /* how to parse and object path? */ > + if ((value.type != CMPI_ref) || CMIsNullObject(value.value.ref)) > + return CMPI_RC_ERR_TYPE_MISMATCH; > + > + *_reference = value.value.ref; > > return CMPI_RC_OK; > } > @@ -305,6 +308,7 @@ static CMPIStatus CreateInstance( > const char *child_name = NULL; > struct acl_filter *child_filter = NULL; > virConnectPtr conn = NULL; > + CMPIObjectPath *_reference = NULL; > > CU_DEBUG("Reference = %s", REF2STR(reference)); > > @@ -383,6 +387,11 @@ static CMPIStatus CreateInstance( > goto out; > } > > + /* create new object path */ > + _reference = CMClone(reference, NULL); > + CMAddKey(_reference, "Antecedent", (CMPIValue *)&antecedent, CMPI_ref); > + CMAddKey(_reference, "Dependent", (CMPIValue *)&dependent, CMPI_ref); > + > CMReturnObjectPath(results, reference); Should be returning _reference right? Another question, is it necessary to free the _reference variable somehow? Looking at Pegasus headers, I can see a CMRelease declaration near CMClone. -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From cvincent at linux.vnet.ibm.com Thu Jan 26 16:50:02 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Thu, 26 Jan 2012 11:50:02 -0500 Subject: [Libvirt-cim] [PATCH v2] Fix AppliedFilterList creation and deletion In-Reply-To: <4F217A8B.50504@linux.vnet.ibm.com> References: <1327589901-28693-1-git-send-email-cvincent@linux.vnet.ibm.com> <4F217A8B.50504@linux.vnet.ibm.com> Message-ID: <4F21843A.6040902@linux.vnet.ibm.com> On 01/26/2012 11:08 AM, Eduardo Lima (Etrunko) wrote: > On 01/26/2012 12:58 PM, Chip Vincent wrote: >> From: Chip Vincent >> >> Fixes many small issues with the current AppliedFilterList provider. >> >> 1) Fix Create to properly return a complete object path and fix Delete to >> properly parse that path. >> >> 2) Persist applied filer rules. Since it's not possible to dyanmically update >> a single device, I've changed the code to modify and re-define the VM to >> essentially add/remove ACL filter associations. >> >> I also updated the code to minimize domain/device parsing overhead. For >> some strange reason, our internal APIs sometimes take a virDomainPtr and >> other times a struct domain * forcing providers who work with domains >> *and* devices to parse everything twice. Until the internal APIs are >> cleaned up, I simply parse everything once and then fetch the device >> manually from the struct domain *. >> >> 3) Add VIR_DOMAIN_XML_INACTIVE to virDomainGetXML(). By default, libvirt only >> returns the XML of the running domain. We need to fetch the *stored* XML >> that will be used for the next boot so that all changes made while the VM >> is running are preserved. >> >> Changes from v1: >> - Fix leak and other comments >> - Fix all cases virDomainGetXML() >> - Fix NestedFilterList Create/Delete instance > Almost there, see below: > > [snip] > >> diff --git a/src/Virt_NestedFilterList.c b/src/Virt_NestedFilterList.c >> index 894cd7c..b72c582 100644 >> --- a/src/Virt_NestedFilterList.c >> +++ b/src/Virt_NestedFilterList.c >> @@ -98,7 +98,10 @@ static CMPIrc cu_get_ref_path(const CMPIObjectPath *reference, >> if ((s.rc != CMPI_RC_OK) || CMIsNullValue(value)) >> return CMPI_RC_ERR_NO_SUCH_PROPERTY; >> >> - /* how to parse and object path? */ >> + if ((value.type != CMPI_ref) || CMIsNullObject(value.value.ref)) >> + return CMPI_RC_ERR_TYPE_MISMATCH; >> + >> + *_reference = value.value.ref; >> >> return CMPI_RC_OK; >> } >> @@ -305,6 +308,7 @@ static CMPIStatus CreateInstance( >> const char *child_name = NULL; >> struct acl_filter *child_filter = NULL; >> virConnectPtr conn = NULL; >> + CMPIObjectPath *_reference = NULL; >> >> CU_DEBUG("Reference = %s", REF2STR(reference)); >> >> @@ -383,6 +387,11 @@ static CMPIStatus CreateInstance( >> goto out; >> } >> >> + /* create new object path */ >> + _reference = CMClone(reference, NULL); >> + CMAddKey(_reference, "Antecedent", (CMPIValue *)&antecedent, CMPI_ref); >> + CMAddKey(_reference, "Dependent", (CMPIValue *)&dependent, CMPI_ref); >> + >> CMReturnObjectPath(results, reference); > Should be returning _reference right? Good catch! Will fix > Another question, is it necessary to free the _reference variable > somehow? Looking at Pegasus headers, I can see a CMRelease declaration > near CMClone. > No. All CMPI objects are released once the request thread is completed. CMRelease() is exposed for symmetry and also for long running threads, like jobs or indication providers. -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From cvincent at linux.vnet.ibm.com Thu Jan 26 16:51:45 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Thu, 26 Jan 2012 11:51:45 -0500 Subject: [Libvirt-cim] [PATCH v3] Fix AppliedFilterList creation and deletion Message-ID: <1327596705-15032-1-git-send-email-cvincent@linux.vnet.ibm.com> From: Chip Vincent Fixes many small issues with the current AppliedFilterList provider. 1) Fix Create to properly return a complete object path and fix Delete to properly parse that path. 2) Persist applied filer rules. Since it's not possible to dyanmically update a single device, I've changed the code to modify and re-define the VM to essentially add/remove ACL filter associations. I also updated the code to minimize domain/device parsing overhead. For some strange reason, our internal APIs sometimes take a virDomainPtr and other times a struct domain * forcing providers who work with domains *and* devices to parse everything twice. Until the internal APIs are cleaned up, I simply parse everything once and then fetch the device manually from the struct domain *. 3) Add VIR_DOMAIN_XML_INACTIVE to virDomainGetXML(). By default, libvirt only returns the XML of the running domain. We need to fetch the *stored* XML that will be used for the next boot so that all changes made while the VM is running are preserved. Changes from v2: - Return the correct reference in NestedFilterList Changes from v1: - Fix leak and other comments - Fix all cases virDomainGetXML() - Fix NestedFilterList Create/Delete instance Signed-off-by: Chip Vincent --- libxkutil/device_parsing.c | 6 ++- src/Virt_AppliedFilterList.c | 97 +++++++++++++++++++---------------- src/Virt_ComputerSystem.c | 3 +- src/Virt_ComputerSystemIndication.c | 3 +- src/Virt_FilterList.c | 5 ++- src/Virt_NestedFilterList.c | 15 ++++- src/Virt_VSMigrationService.c | 3 +- 7 files changed, 79 insertions(+), 53 deletions(-) diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c index a1e8d6c..ff86f2a 100644 --- a/libxkutil/device_parsing.c +++ b/libxkutil/device_parsing.c @@ -996,7 +996,8 @@ int get_devices(virDomainPtr dom, struct virt_device **list, int type) char *xml; int ret; - xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_SECURE); + xml = virDomainGetXMLDesc(dom, + VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); if (xml == NULL) return 0; @@ -1241,7 +1242,8 @@ int get_dominfo(virDomainPtr dom, struct domain **dominfo) char *xml; int ret; int start; - xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_SECURE); + xml = virDomainGetXMLDesc(dom, + VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); if (xml == NULL) return 0; diff --git a/src/Virt_AppliedFilterList.c b/src/Virt_AppliedFilterList.c index bc31c14..538adf4 100644 --- a/src/Virt_AppliedFilterList.c +++ b/src/Virt_AppliedFilterList.c @@ -97,67 +97,60 @@ static CMPIrc cu_get_ref_path(const CMPIObjectPath *reference, if ((s.rc != CMPI_RC_OK) || CMIsNullValue(value)) return CMPI_RC_ERR_NO_SUCH_PROPERTY; - /* how to parse and object path? */ + if ((value.type != CMPI_ref) || CMIsNullObject(value.value.ref)) + return CMPI_RC_ERR_TYPE_MISMATCH; + + *_reference = value.value.ref; return CMPI_RC_OK; } -/* TODO: Port to libxkutil/device_parsing.c */ -static int update_device(virDomainPtr dom, - struct virt_device *dev) +static int update_domain(virConnectPtr conn, + struct domain *dominfo) { -#if LIBVIR_VERSION_NUMBER > 8000 char *xml = NULL; - int flags = VIR_DOMAIN_DEVICE_MODIFY_CURRENT | - VIR_DOMAIN_DEVICE_MODIFY_CONFIG; - int ret = 0; + virDomainPtr dom = NULL; - xml = device_to_xml(dev); + xml = system_to_xml(dominfo); if (xml == NULL) { - CU_DEBUG("Failed to get XML for device '%s'", dev->id); + CU_DEBUG("Failed to get XML from domain %s", dominfo->name); goto out; } - if (virDomainUpdateDeviceFlags(dom, xml, flags) != 0) { - CU_DEBUG("Failed to dynamically update device"); + dom = virDomainDefineXML(conn, xml); + if (dom == NULL) { + CU_DEBUG("Failed to update domain %s", dominfo->name); goto out; } - ret = 1; out: free(xml); + virDomainFree(dom); - return ret; -#else return 0; -#endif } -/* TODO: Port to libxkutil/device_parsing.c */ -static int get_device_by_devid(virDomainPtr dom, +static int get_device_by_devid(struct domain *dominfo, const char *devid, - int type, struct virt_device **dev) { - int i, ret = 0; - struct virt_device *devices = NULL; - int count = get_devices(dom, &devices, type); + int i; + struct virt_device *devices = dominfo->dev_net; + int count = dominfo->dev_net_ct; + + if (dev == NULL) + return 0; for (i = 0; i < count; i++) { if (STREQC(devid, devices[i].id)) { CU_DEBUG("Found '%s'", devices[i].id); - *dev = virt_device_dup(&devices[i]); - if (*dev != NULL) - ret = 1; - - break; + *dev = &devices[i]; + return 0; } } - cleanup_virt_devices(&devices, count); - - return ret; + return 1; } /** @@ -425,6 +418,8 @@ static CMPIStatus CreateInstance( struct virt_device *device = NULL; virConnectPtr conn = NULL; virDomainPtr dom = NULL; + struct domain *dominfo = NULL; + CMPIObjectPath *_reference = NULL; conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s); if (conn == NULL) @@ -487,8 +482,12 @@ static CMPIStatus CreateInstance( goto out; } - get_device_by_devid(dom, net_name, CIM_RES_TYPE_NET, &device); - if (device == NULL) { + if (get_dominfo(dom, &dominfo) == 0) { + CU_DEBUG("Failed to get dominfo"); + goto out; + } + + if (get_device_by_devid(dominfo, net_name, &device) != 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, "Dependent.Name object does not exist"); @@ -502,14 +501,19 @@ static CMPIStatus CreateInstance( device->dev.net.filter_ref = strdup(filter_name); - if (update_device(dom, device) == 0) { + if (update_domain(conn, dominfo) != 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, - "Failed to update device"); + "Failed to update domain"); goto out; } - CMReturnObjectPath(results, reference); + /* create new object path */ + _reference = CMClone(reference, NULL); + CMAddKey(_reference, "Antecedent", (CMPIValue *)&antecedent, CMPI_ref); + CMAddKey(_reference, "Dependent", (CMPIValue *)&dependent, CMPI_ref); + + CMReturnObjectPath(results, _reference); CU_DEBUG("CreateInstance complete"); out: @@ -542,6 +546,7 @@ static CMPIStatus DeleteInstance( struct virt_device *device = NULL; virConnectPtr conn = NULL; virDomainPtr dom = NULL; + struct domain *dominfo = NULL; conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s); if (conn == NULL) @@ -557,7 +562,7 @@ static CMPIStatus DeleteInstance( goto out; } - if (cu_get_str_path(reference, "DeviceID", + if (cu_get_str_path(antecedent, "DeviceID", &device_name) != CMPI_RC_OK) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, @@ -573,7 +578,7 @@ static CMPIStatus DeleteInstance( goto out; } - if (cu_get_str_path(reference, "Name", + if (cu_get_str_path(dependent, "Name", &filter_name) != CMPI_RC_OK) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, @@ -585,7 +590,7 @@ static CMPIStatus DeleteInstance( if (filter == NULL) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, - "Antecedent.Name object does not exist"); + "Dependent.Name object does not exist"); goto out; } @@ -600,11 +605,15 @@ static CMPIStatus DeleteInstance( goto out; } - get_device_by_devid(dom, net_name, CIM_RES_TYPE_NET, &device); - if (device == NULL) { + if (get_dominfo(dom, &dominfo) == 0) { + CU_DEBUG("Failed to get dominfo"); + goto out; + } + + if (get_device_by_devid(dominfo, net_name, &device) != 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, - "Dependent.Name object does not exist"); + "Antecedent.Name object does not exist"); goto out; } @@ -613,14 +622,14 @@ static CMPIStatus DeleteInstance( device->dev.net.filter_ref = NULL; } - if (update_device(dom, device) == 0) { + if (update_domain(conn, dominfo) != 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, - "Failed to update device"); + "Failed to update domain"); goto out; } - CU_DEBUG("CreateInstance complete"); + CU_DEBUG("DeleteInstance complete"); out: free(domain_name); diff --git a/src/Virt_ComputerSystem.c b/src/Virt_ComputerSystem.c index 582253a..e6c7e55 100644 --- a/src/Virt_ComputerSystem.c +++ b/src/Virt_ComputerSystem.c @@ -926,7 +926,8 @@ static CMPIStatus domain_reset(virDomainPtr dom) return s; } - xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_SECURE); + xml = virDomainGetXMLDesc(dom, + VIR_DOMAIN_XML_INACTIVE |VIR_DOMAIN_XML_SECURE); if (xml == NULL) { CU_DEBUG("Unable to retrieve domain XML"); virt_set_status(_BROKER, &s, diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c index eb1a71c..6ef2ddc 100644 --- a/src/Virt_ComputerSystemIndication.c +++ b/src/Virt_ComputerSystemIndication.c @@ -107,7 +107,8 @@ static int csi_dom_xml_set(csi_dom_xml_t *dom, virDomainPtr dom_ptr, CMPIStatus dom->name = strdup(name); /* xml */ - dom->xml = virDomainGetXMLDesc(dom_ptr, VIR_DOMAIN_XML_SECURE); + dom->xml = virDomainGetXMLDesc(dom_ptr, + VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); if (dom->xml == NULL) { cu_statusf(_BROKER, s, CMPI_RC_ERR_FAILED, diff --git a/src/Virt_FilterList.c b/src/Virt_FilterList.c index 35d18a9..5b1b6e8 100644 --- a/src/Virt_FilterList.c +++ b/src/Virt_FilterList.c @@ -358,7 +358,10 @@ static CMPIStatus DeleteInstance( goto out; } - delete_filter(conn, filter); + if (delete_filter(conn, filter) != 0) { + CU_DEBUG("Failed to delete filter %s", filter->name); + goto out; + } out: cleanup_filters(&filter, 1); diff --git a/src/Virt_NestedFilterList.c b/src/Virt_NestedFilterList.c index 894cd7c..2353e61 100644 --- a/src/Virt_NestedFilterList.c +++ b/src/Virt_NestedFilterList.c @@ -98,7 +98,10 @@ static CMPIrc cu_get_ref_path(const CMPIObjectPath *reference, if ((s.rc != CMPI_RC_OK) || CMIsNullValue(value)) return CMPI_RC_ERR_NO_SUCH_PROPERTY; - /* how to parse and object path? */ + if ((value.type != CMPI_ref) || CMIsNullObject(value.value.ref)) + return CMPI_RC_ERR_TYPE_MISMATCH; + + *_reference = value.value.ref; return CMPI_RC_OK; } @@ -305,6 +308,7 @@ static CMPIStatus CreateInstance( const char *child_name = NULL; struct acl_filter *child_filter = NULL; virConnectPtr conn = NULL; + CMPIObjectPath *_reference = NULL; CU_DEBUG("Reference = %s", REF2STR(reference)); @@ -383,7 +387,12 @@ static CMPIStatus CreateInstance( goto out; } - CMReturnObjectPath(results, reference); + /* create new object path */ + _reference = CMClone(reference, NULL); + CMAddKey(_reference, "Antecedent", (CMPIValue *)&antecedent, CMPI_ref); + CMAddKey(_reference, "Dependent", (CMPIValue *)&dependent, CMPI_ref); + + CMReturnObjectPath(results, _reference); CU_DEBUG("CreateInstance completed"); out: @@ -475,7 +484,7 @@ static CMPIStatus DeleteInstance( goto out; } - CU_DEBUG("CreateInstance completed"); + CU_DEBUG("DeleteInstance completed"); out: cleanup_filters(&parent_filter, 1); diff --git a/src/Virt_VSMigrationService.c b/src/Virt_VSMigrationService.c index d393787..76e3d25 100644 --- a/src/Virt_VSMigrationService.c +++ b/src/Virt_VSMigrationService.c @@ -1070,7 +1070,8 @@ static CMPIStatus prepare_migrate(virDomainPtr dom, { CMPIStatus s = {CMPI_RC_OK, NULL}; - *xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_SECURE); + *xml = virDomainGetXMLDesc(dom, + VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); if (*xml == NULL) { virt_set_status(_BROKER, &s, -- 1.7.1 From snmishra at linux.vnet.ibm.com Thu Jan 26 18:36:08 2012 From: snmishra at linux.vnet.ibm.com (Sharad Mishra) Date: Thu, 26 Jan 2012 10:36:08 -0800 Subject: [Libvirt-cim] [PATCH v5] vlan extention - add function library for readonly usage In-Reply-To: <1327521897-17291-1-git-send-email-xiaxia347work@163.com> References: <1327521897-17291-1-git-send-email-xiaxia347work@163.com> Message-ID: <1327602968.4193.1265.camel@snmishra-desktop.beaverton.ibm.com> Code looks good. I have marked some nits. Take a look. I have not yet applied the patch or done any testing. When do we see the actual provider? This patch is more of a backend/infrastructure. We will also need a CIM layer. -Sharad Mishra On Thu, 2012-01-26 at 04:04 +0800, xiaxia347work at 163.com wrote: > From: Wenchao Xia > > This patch contain 1 test program and 1 c file doing xml and structure > mapping. It expose some API to translate xml to device structure, in a similar > way to code in device_parsing.c. Also some other files are changed to let new > code use their internal functions. Type following Command in libxkutil > directory: > sudo CU_DEBUG=stdout .libs/network_parsing_test > could see what it have done. > > v5: calling libvirt API which employ netcf instead of using libnl. From git log > these API are available since 0.9.2, and this patch is tested with libvirt > 0.9.4. > > Signed-off-by: Wenchao Xia > --- > libxkutil/Makefile.am | 12 +- > libxkutil/misc_util.c | 10 +- > libxkutil/network_parsing.c | 665 ++++++++++++++++++++++++++++++++++++++ > libxkutil/network_parsing.h | 160 +++++++++ > libxkutil/network_parsing_test.c | 61 ++++ > libxkutil/xmlgen.c | 2 +- > libxkutil/xmlgen.h | 2 + > 7 files changed, 906 insertions(+), 6 deletions(-) > create mode 100644 libxkutil/network_parsing.c > create mode 100644 libxkutil/network_parsing.h > create mode 100644 libxkutil/network_parsing_test.c > > diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am > index f1adc03..c0e62eb 100644 > --- a/libxkutil/Makefile.am > +++ b/libxkutil/Makefile.am > @@ -4,12 +4,14 @@ AM_CFLAGS = $(CFLAGS_STRICT) \ > -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" > > noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ > - pool_parsing.h acl_parsing.h > + pool_parsing.h acl_parsing.h \ > + network_parsing.h > > lib_LTLIBRARIES = libxkutil.la > > libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ > - xmlgen.c infostore.c pool_parsing.c acl_parsing.c > + xmlgen.c infostore.c pool_parsing.c acl_parsing.c \ > + network_parsing.c > libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ > libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ > @LIBUUID_LIBS@ > @@ -19,3 +21,9 @@ noinst_PROGRAMS = xml_parse_test > xml_parse_test_SOURCES = xml_parse_test.c > xml_parse_test_LDADD = libxkutil.la \ > @LIBVIRT_LIBS@ > + > +noinst_PROGRAMS += network_parsing_test > + > +network_parsing_test_SOURCES = network_parsing_test.c > +network_parsing_test_LDADD = libxkutil.la \ > + @LIBVIRT_LIBS@ > diff --git a/libxkutil/misc_util.c b/libxkutil/misc_util.c > index 61893c3..1c18c33 100644 > --- a/libxkutil/misc_util.c > +++ b/libxkutil/misc_util.c > @@ -152,9 +152,13 @@ virConnectPtr connect_by_classname(const CMPIBroker *broker, > > uri = cn_to_uri(classname); > if (!uri) { > - cu_statusf(broker, s, > - CMPI_RC_ERR_FAILED, > - "Unable to generate URI from classname"); > + if (broker) { > + cu_statusf(broker, s, > + CMPI_RC_ERR_FAILED, > + "Unable to generate URI from classname"); > + } > + CU_DEBUG("Unable to generate URI from classname," > + " uri is %s.", uri); > return NULL; > } > > diff --git a/libxkutil/network_parsing.c b/libxkutil/network_parsing.c > new file mode 100644 > index 0000000..932000c > --- /dev/null > +++ b/libxkutil/network_parsing.c > @@ -0,0 +1,665 @@ > +/* > + * Copyright IBM Corp. 2012 > + * > + * Authors: > + * Wenchao Xia > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > + */ > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > + > +#include "misc_util.h" > +#include "xmlgen.h" > +#include "device_parsing.h" > +#include "network_parsing.h" > + > +#define XML_ERROR "Failed to allocate XML memory" > + > +static void vlan_prop_print(struct VLAN_Prop *pvlan_prop) > +{ > + struct VLAN_Prop_8021q *p_8021q; > + CMD_DEBUG(1, "--VLAN props: type %d.\n", > + pvlan_prop->vlan_type); > + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { > + p_8021q = &(pvlan_prop->props.prop_8021q); > + CMD_DEBUG(1, "----IEEE802.1.Q: id %d, parent %s.\n", > + p_8021q->vlan_id, p_8021q->parent); > + } > +} > + > +static void br_prop_print(struct BR_Prop *pbr_prop) > +{ > + int i = 0; > + CMD_DEBUG(1, "--Bridge props: stp %d, delay %d, port_num %d.\n", > + pbr_prop->STP, pbr_prop->delay, pbr_prop->port_num); > + if (pbr_prop->port_names != NULL) { > + CMD_DEBUG(1, "----Ports attached: "); > + while (i < pbr_prop->port_num) { > + CMD_DEBUG(1, " %s,", *(pbr_prop->port_names+i)); > + i++; > + } > + CMD_DEBUG(1, "\n"); > + } > +} > + > +void eth_iface_print(struct EthIface *piface) > +{ > + CMD_DEBUG(1, "Iface device: name %s.\n" > + "--Main Props: parent %s, attach to %s, mac %s," > + " status %d, boot_mode %d, iface type 0x%x.\n", > + piface->name, piface->dep_ifname, piface->attach_bridge, > + piface->mac, > + piface->run_prop.status, piface->run_prop.boot_mode, piface->eth_type); > + if (piface->pbr_prop != NULL) { > + br_prop_print(piface->pbr_prop); > + } > + if (piface->pvlan_prop != NULL) { > + vlan_prop_print(piface->pvlan_prop); > + } > + return; > +} > + > +void eth_ifaceslist_print(struct EthIfacesList *plist) > +{ > + int i = 0; > + CMD_DEBUG(1, "Have %d ifaces in the list:\n", plist->count); > + while (i < plist->count) { > + CMD_DEBUG(1, "%04d ", i); > + eth_iface_print(plist->pifaces[i]); > + i++; > + } > +} > + > +static void vlan_prop_init(struct VLAN_Prop *pvlan_prop, int vlan_type) > +{ > + struct VLAN_Prop_8021q *p_8021q; > + memset(pvlan_prop, 0, sizeof(struct VLAN_Prop)); > + pvlan_prop->vlan_type = vlan_type; > + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { > + p_8021q = &(pvlan_prop->props.prop_8021q); > + p_8021q->vlan_id = NUM_NOT_GOT; > + } > +} > + > +static void br_prop_init(struct BR_Prop *pbr_prop) > +{ > + memset(pbr_prop, 0, sizeof(struct BR_Prop)); > + pbr_prop->STP = NUM_NOT_GOT; > + pbr_prop->delay = NUM_NOT_GOT; > + pbr_prop->port_num = NUM_NOT_GOT; > +} > + > +void eth_iface_init(struct EthIface *piface) > +{ > + memset(piface, 0, sizeof(struct EthIface)); > + piface->eth_type = ETH_TYPE_NOT_GOT; > + piface->run_prop.status = NUM_NOT_GOT; > + piface->run_prop.boot_mode = BOOT_MODE_NOT_GOT; > + return; > +} > + > +void eth_iface_add_br_prop(struct EthIface *piface) > +{ > + if (piface->pbr_prop != NULL) { > + return; > + } > + SAFE_MALLOC(piface->pbr_prop, sizeof(struct BR_Prop)); > + br_prop_init(piface->pbr_prop); > +} > + > +void eth_iface_add_vlan_prop(struct EthIface *piface, int vlan_type) > +{ > + if (piface->pvlan_prop != NULL) { > + return; > + } > + SAFE_MALLOC(piface->pvlan_prop, sizeof(struct VLAN_Prop)); > + vlan_prop_init(piface->pvlan_prop, vlan_type); > +} > + > +static void vlan_prop_uninit(struct VLAN_Prop *pvlan_prop) > +{ > + struct VLAN_Prop_8021q *p_8021q; > + if (pvlan_prop == NULL) { > + return; > + } > + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { > + p_8021q = &(pvlan_prop->props.prop_8021q); > + SAFE_FREE(p_8021q->parent); > + } > +} > + > +static void br_prop_uninit(struct BR_Prop *pbr_prop) > +{ > + int i; > + if (pbr_prop == NULL) { > + return; > + } > + i = 0; > + if (pbr_prop->port_names != NULL) { > + while (i < pbr_prop->port_num) { > + SAFE_FREE(pbr_prop->port_names[i]); > + i++; > + } > + SAFE_FREE(pbr_prop->port_names); > + } > +} > + > +void eth_iface_uninit(struct EthIface *piface) > +{ > + if (piface == NULL) { > + return; > + } > + SAFE_FREE(piface->name); > + SAFE_FREE(piface->dep_ifname); > + SAFE_FREE(piface->attach_bridge); > + SAFE_FREE(piface->mac); > + br_prop_uninit(piface->pbr_prop); > + SAFE_FREE(piface->pbr_prop); > + vlan_prop_uninit(piface->pvlan_prop); > + SAFE_FREE(piface->pvlan_prop); > + return; > +} > + > +void eth_ifaceslist_init(struct EthIfacesList *plist) > +{ > + plist->count = 0; > +} > + > +void eth_ifaceslist_uninit(struct EthIfacesList *plist) > +{ > + struct EthIface **t; > + int i; > + if (plist->count <= 0) { > + return; > + } > + t = plist->pifaces; > + i = 0; > + while (i < plist->count) { > + if (*t != NULL) { > + eth_iface_uninit(*t); > + SAFE_FREE(*t); > + } > + t++; > + i++; > + } > + return; > +} > + > +int eth_ifaceslist_add(struct EthIfacesList *plist, struct EthIface **ppiface) > +{ > + if (plist->count >= MAX_IFACE_NUM) { > + CU_DEBUG("too much device found."); > + return 0; > + } > + plist->pifaces[plist->count] = *ppiface; > + *ppiface = NULL; > + plist->count++; > + return 1; > +} > + > +struct EthIface *eth_ifaceslist_search(struct EthIfacesList *plist, > + char *name) > +{ > + int i = 0; > + struct EthIface *piface = NULL; > + > + while (i < plist->count) { > + piface = plist->pifaces[i]; > + i++; > + if (piface != NULL) { > + if (0 == strcmp(piface->name, name)) { can we do "if (strcmp(piface->name, name) == 0) { " ? > + return piface; > + } > + } > + } > + return NULL; > +} > + > +/* Dummy function to suppress error message from libxml2 */ > +static void swallow_err_msg(void *ctx, const char *msg, ...) > +{ > + /* do nothing, just swallow the message. */ > +} > + > + > +static const char *gen_eth_xmlnode_iface(xmlNodePtr root, > + struct EthIface *piface, > + struct EthIfacesList *plist, > + int bridge_port_flag) > +{ > + const char *msg = NULL; > + xmlNodePtr temp_node1 = NULL, temp_node2 = NULL, temp_node3 = NULL; > + char *str, buf[16]; > + int i; > + struct EthIface *pifaceport; > + > + if (piface->name == NULL) { > + msg = "iface have no name.\n"; > + goto out; > + } > + /* netcfg have no xml for iface attatched to bridge */ > + if ((piface->attach_bridge != NULL) && (bridge_port_flag != 1)) { What are you trying to eliminate here? > + goto out; > + } > + > + temp_node1 = xmlNewChild(root, NULL, BAD_CAST "interface", NULL); > + if (temp_node1 == NULL) { > + msg = XML_ERROR; > + goto out; > + } > + xmlNewProp(temp_node1, BAD_CAST "name", BAD_CAST piface->name); > + if (piface->eth_type & ETH_TYPE_ETHER_ANY) { why do we require the above check? Can it be eliminated and just use the checks below? > + if (piface->eth_type & ETH_TYPE_ETHER_SUB_BRIDGE) { > + str = "bridge"; > + } else if (piface->eth_type & ETH_TYPE_ETHER_SUB_VLAN) { > + str = "vlan"; > + } else { > + str = "ethernet"; > + } > + xmlNewProp(temp_node1, BAD_CAST "type", BAD_CAST str); > + } > + > + if ((piface->pvlan_prop != NULL) && > + (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q)) { > + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "vlan", NULL); > + snprintf(buf, sizeof(buf), > + "%d", piface->pvlan_prop->props.prop_8021q.vlan_id); > + xmlNewProp(temp_node2, BAD_CAST "tag", BAD_CAST buf); > + temp_node3 = xmlNewChild(temp_node2, NULL, BAD_CAST "interface", NULL); > + xmlNewProp(temp_node3, BAD_CAST "name", > + BAD_CAST piface->pvlan_prop->props.prop_8021q.parent); > + } > + > + /* if it is attached to bridge, only above properties could be set */ > + if (bridge_port_flag == 1) { > + goto out; > + } > + > + if (piface->pbr_prop != NULL) { > + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "bridge", NULL); > + if (piface->pbr_prop->STP == 1) { > + snprintf(buf, sizeof(buf), "on"); > + } else { > + snprintf(buf, sizeof(buf), "off"); > + } > + xmlNewProp(temp_node2, BAD_CAST "stp", BAD_CAST buf); > + if (piface->pbr_prop->delay >= 0) { > + snprintf(buf, sizeof(buf), "%d", piface->pbr_prop->delay); > + xmlNewProp(temp_node2, BAD_CAST "delay", BAD_CAST buf); > + } > + if ((piface->pbr_prop->port_names != NULL) && > + (piface->pbr_prop->port_num > 0)) { > + for (i = 0; i < piface->pbr_prop->port_num; i++) { > + pifaceport = eth_ifaceslist_search(plist, > + piface->pbr_prop->port_names[i]); > + if (pifaceport == NULL) { > + CU_DEBUG("failed to find port %s of bridge %s in list.", > + piface->pbr_prop->port_names[i], piface->name); > + } else { > + gen_eth_xmlnode_iface(temp_node2, pifaceport, plist, 1); > + } > + } > + } > + } > + > + if (piface->run_prop.boot_mode == BOOT_MODE_AUTOSTART) { > + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "start", NULL); > + xmlNewProp(temp_node2, BAD_CAST "mode", BAD_CAST "onboot"); > + } else if (piface->run_prop.boot_mode == BOOT_MODE_NONE) { > + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "start", NULL); > + xmlNewProp(temp_node2, BAD_CAST "mode", BAD_CAST "none"); > + } > + if (piface->mac != NULL) { > + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "mac", NULL); > + xmlNewProp(temp_node2, BAD_CAST "address", BAD_CAST piface->mac); > + } > + > + out: > + return msg; > +} > + > +static const char *gen_eth_xmlnode(xmlNodePtr root, > + struct EthIfacesList *plist) > +{ > + const char *msg = NULL; > + int i = 0; > + struct EthIface *piface = NULL; > + > + while (i < plist->count) { > + piface = plist->pifaces[i]; > + i++; > + msg = gen_eth_xmlnode_iface(root, piface, plist, 0); > + if (msg != NULL) { > + goto out; > + } > + } > + > + out: > + return msg; > +} > + > +const char *EthIfaceListTOXML(char **ppxml, > + struct EthIfacesList *plist, > + int dump_all_flag) > +{ > + const char *msg = NULL; > + xmlNodePtr root = NULL; > + > + root = xmlNewNode(NULL, BAD_CAST "tmp"); > + if (root == NULL) { > + msg = "failed to create root node."; > + goto out; > + } > + msg = gen_eth_xmlnode(root, plist); > + if (msg == NULL) { > + if (dump_all_flag == 1) { > + *ppxml = tree_to_xml(root); > + } else { > + *ppxml = tree_to_xml(root->children); > + } > + } > + > + out: > + xmlFreeNode(root); > + return msg; > +} > + > +static int parse_eth_xmlnode(struct EthIfacesList *plist, xmlNode *inode, > + int status, char *attached) > +{ > + struct EthIface *piface = NULL; > + xmlNode *child1 = NULL, *child2 = NULL; > + char *temp = NULL, **ppchar; > + > + SAFE_MALLOC(piface, sizeof(struct EthIface)); > + eth_iface_init(piface); > + > + piface->name = get_attr_value(inode, "name"); > + piface->run_prop.status = status; > + if (attached != NULL) { > + piface->attach_bridge = strdup(attached); > + } > + temp = get_attr_value(inode, "type"); > + if (temp != NULL) { > + if (0 == strcmp(temp, "ethernet")) { can you change to if(strcmp() == 0) > + piface->eth_type = ETH_TYPE_ETHER_ANY; > + } > + if (0 == strcmp(temp, "bridge")) { > + piface->eth_type = ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_BRIDGE; > + } > + if (0 == strcmp(temp, "vlan")) { > + piface->eth_type = ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_VLAN; > + } > + SAFE_FREE(temp); > + } > + > + for (child1 = inode->children; child1 != NULL; child1 = child1->next) { > + if (XSTREQ(child1->name, "start")) { > + temp = get_attr_value(child1, "mode"); > + if (0 == strcmp(temp, "onboot")) { change as above > + piface->run_prop.boot_mode = BOOT_MODE_AUTOSTART; > + } > + if (0 == strcmp(temp, "none")) { > + piface->run_prop.boot_mode = BOOT_MODE_NONE; > + } > + SAFE_FREE(temp); > + } > + if (XSTREQ(child1->name, "mac")) { > + piface->mac = get_attr_value(child1, "address"); > + } > + if (XSTREQ(child1->name, "bridge")) { > + eth_iface_add_br_prop(piface); > + temp = get_attr_value(child1, "stp"); > + if (0 == strcmp(temp, "on")) { > + piface->pbr_prop->STP = 1; > + } > + if (0 == strcmp(temp, "off")) { > + piface->pbr_prop->STP = 0; > + } > + SAFE_FREE(temp); > + temp = get_attr_value(child1, "delay"); > + piface->pbr_prop->delay = strtol(temp, NULL, 10); > + SAFE_FREE(temp); > + } > + if (XSTREQ(child1->name, "bridge")) { > + eth_iface_add_br_prop(piface); > + temp = get_attr_value(child1, "stp"); > + if (0 == strcmp(temp, "on")) { > + piface->pbr_prop->STP = 1; > + } > + if (0 == strcmp(temp, "off")) { > + piface->pbr_prop->STP = 0; > + } > + SAFE_FREE(temp); > + temp = get_attr_value(child1, "delay"); > + piface->pbr_prop->delay = strtol(temp, NULL, 10); > + SAFE_FREE(temp); > + for (child2 = child1->children; child2 != NULL; > + child2 = child2->next) { > + if (XSTREQ(child2->name, "interface")) { > + if (piface->pbr_prop->port_names == NULL) { > + SAFE_CALLOC(piface->pbr_prop->port_names, > + MAX_IFACE_NUM, sizeof(char *)); > + piface->pbr_prop->port_num = 0; > + } > + ppchar = piface->pbr_prop->port_names + > + (piface->pbr_prop->port_num)++; > + *ppchar = get_attr_value(child2, "name"); > + parse_eth_xmlnode(plist, child2, status, piface->name); > + } > + } > + } > + if (XSTREQ(child1->name, "vlan")) { > + eth_iface_add_vlan_prop(piface, VLAN_TYPE_802_1_Q); > + temp = get_attr_value(child1, "tag"); > + piface->pvlan_prop->props.prop_8021q.vlan_id = > + strtol(temp, NULL, 10); > + SAFE_FREE(temp); > + for (child2 = child1->children; child2 != NULL; > + child2 = child2->next) { > + if (XSTREQ(child2->name, "interface")) { > + piface->pvlan_prop->props.prop_8021q.parent = > + get_attr_value(child2, "name"); > + piface->dep_ifname = > + get_attr_value(child2, "name"); > + } > + } > + } > + } > + > + eth_ifaceslist_add(plist, &piface); > + return 1; > +} > + > +static const char *XMLToEthIfaceList(struct EthIfacesList *plist, > + const char *xml, > + int status) > +{ > + xmlDoc *xmldoc; > + xmlXPathContext *xpathCtx; > + xmlXPathObject *xpathObj; > + xmlChar *xpathstr; > + xmlNode **dev_nodes = NULL; > + xmlNodeSet *nsv = NULL; > + int count = 0; > + int len, devidx; > + const char *msg = NULL; > + > + len = strlen(xml) + 1; > + xpathstr = (xmlChar *)"/interface"; > + > + xmlSetGenericErrorFunc(NULL, swallow_err_msg); > + if ((xmldoc = xmlParseMemory(xml, len)) == NULL) { > + msg = "failed to get xmldoc."; > + goto err1; > + } > + > + if ((xpathCtx = xmlXPathNewContext(xmldoc)) == NULL) { > + msg = "failed to get pathCtx"; > + goto err2; > + } > + > + if ((xpathObj = xmlXPathEvalExpression(xpathstr, xpathCtx)) > + == NULL) { > + msg = "failed to get xpathObj"; > + goto err3; > + } > + > + nsv = xpathObj->nodesetval; > + if (nsv == NULL) { > + msg = "failed to get nodesetval."; > + goto out; > + } > + > + dev_nodes = nsv->nodeTab; > + count = nsv->nodeNr; > + > + if (count <= 0) { > + msg = "nodesetval have less that 1 values."; > + goto out; > + } > + > + for (devidx = 0; devidx < count; devidx++) { > + parse_eth_xmlnode(plist, dev_nodes[devidx], status, NULL); > + } > + > + out: > + xmlSetGenericErrorFunc(NULL, NULL); > + xmlXPathFreeObject(xpathObj); > + > + err3: > + xmlXPathFreeContext(xpathCtx); > + err2: > + xmlFreeDoc(xmldoc); > + err1: > + return msg; > +} > + > +CMPIStatus get_host_ifaces(struct EthIfacesList *plist, > + const CMPIBroker *broker, char *prefix) > +{ > + virConnectPtr conn = NULL; > + virInterfacePtr iface; > + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; > + int num, listnum, i; > + char **names = NULL; > + char *dump = NULL; > + int flags = 0; > + const char *msg; > + > + conn = connect_by_classname(broker, prefix, &s); > + if (conn == NULL) { > + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, "connect failed."); > + goto out; > + } > + > + /* list defined interfaces*/ > + num = virConnectNumOfDefinedInterfaces(conn); > + if (num < 0) { > + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, > + "failed to find number of defined interfaces."); > + goto out; > + } > + names = malloc(num * sizeof(char *)); > + listnum = virConnectListDefinedInterfaces(conn, names, num); > + if (listnum < 0) { > + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, > + "failed to list names of defined interfaces."); > + goto out; > + } > + CU_DEBUG("%d defined ifaces found from libvirt API.\n", listnum); > + > + flags |= VIR_INTERFACE_XML_INACTIVE; > + for (i = 0; i < listnum; i++) { > + iface = virInterfaceLookupByName(conn, names[i]); > + if (!iface) { > + CU_DEBUG("failed to look up %s.\n", names[i]); > + SAFE_FREE(names[i]); > + continue; > + } > + SAFE_FREE(names[i]); > + dump = virInterfaceGetXMLDesc(iface, flags); > + CU_DEBUG("defined interface %d xml:\n%s", i, dump); > + msg = XMLToEthIfaceList(plist, dump, 0); > + if (msg != NULL) { > + CU_DEBUG("failed parsing eth xml, msg is: %s.", msg); > + } > + SAFE_FREE(dump); > + virInterfaceFree(iface); > + } > + SAFE_FREE(names); > + > + /* list active interfaces*/ > + num = virConnectNumOfInterfaces(conn); > + if (num < 0) { > + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, > + "failed to find number of active interfaces."); > + goto out; > + } > + names = malloc(num * sizeof(char *)); > + > + listnum = virConnectListInterfaces(conn, names, num); > + if (listnum < 0) { > + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, > + "failed to list names of active interfacess."); > + goto out; > + } > + CU_DEBUG("%d active ifaces found from libvirt API.\n", listnum); > + > + flags |= VIR_INTERFACE_XML_INACTIVE; > + for (i = 0; i < listnum; i++) { > + iface = virInterfaceLookupByName(conn, names[i]); > + if (!iface) { > + CU_DEBUG("failed to look up %s.\n", names[i]); > + SAFE_FREE(names[i]); > + continue; > + } > + SAFE_FREE(names[i]); > + dump = virInterfaceGetXMLDesc(iface, flags); > + CU_DEBUG("active interface %d xml:\n%s", i, dump); > + msg = XMLToEthIfaceList(plist, dump, 1); > + if (msg != NULL) { > + CU_DEBUG("failed parsing eth xml, msg is: %s.", msg); > + } > + SAFE_FREE(dump); > + virInterfaceFree(iface); > + } > + s.rc = CMPI_RC_OK; > + > + out: > + virConnectClose(conn); > + SAFE_FREE(names); > + return s; > +} > +/* > + * Local Variables: > + * mode: C > + * c-set-style: "K&R" > + * tab-width: 8 > + * c-basic-offset: 8 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/libxkutil/network_parsing.h b/libxkutil/network_parsing.h > new file mode 100644 > index 0000000..bbfe729 > --- /dev/null > +++ b/libxkutil/network_parsing.h > @@ -0,0 +1,160 @@ > +/* > + * Copyright IBM Corp. 2012 > + * > + * Authors: > + * Wenchao Xia > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + */ > + > +#ifndef NETWORK_PARSING_H > +#define NETWORK_PARSING_H > + > +#include > +#include > +#include > + > +/* value defines */ > +#define MAX_IFACE_NUM 4096 > + > +#define NUM_NOT_GOT -1 > + > +#define ETH_TYPE_BASE_MASK 0xff00 > +#define ETH_TYPE_SUB_MASK 0x00ff > + > +#define CMD_DEBUG_LEVEL 2 > + > +/* macro functions */ > +#define CMD_DEBUG(lvl, fmt, args...) do { \ > + if (CMD_DEBUG_LEVEL && (lvl) <= CMD_DEBUG_LEVEL) { \ > + debug_print(fmt, ##args); \ > + } \ > +} while (0) > + > +#define SAFE_MALLOC(p, size) \ > +{ \ > + (p) = malloc((size)); \ > + if ((p) == NULL) { \ > + CU_DEBUG("malloc failed."); \ > + } \ > +} > + > +#define SAFE_CALLOC(p, nmen, size) \ > +{ \ > + (p) = calloc((nmen), (size)); \ > + if ((p) == NULL) { \ > + CU_DEBUG("calloc failed."); \ > + } \ > +} > + > +#define SAFE_FREE(p) {free(p); (p) = NULL; } > + > +#define RECORD_MSG(broker, ps, rc, fmt, args...) do { \ > + CU_DEBUG(fmt, ##args); \ > + if (broker) { \ > + cu_statusf((broker), (ps), (rc), fmt, ##args); \ > + } \ > +} while (0) > + > +typedef enum { > + ETH_TYPE_NOT_GOT = 0x0000, > + ETH_TYPE_ETHER_ANY = 0x0100, > + ETH_TYPE_ETHER_SUB_PHYSICAL = 0x0001, > + ETH_TYPE_ETHER_SUB_BRIDGE = 0x0002, > + ETH_TYPE_ETHER_SUB_VLAN = 0x0004 > +} EthType; > + > +typedef enum { > + VLAN_TYPE_NOT_GOT = NUM_NOT_GOT, > + VLAN_TYPE_802_1_Q = 1, > + VLAN_TYPE_802_1_QBG = 2, > + VLAN_TYPE_802_1_QBH = 4 > +} VLANType; > + > +typedef enum { > + BOOT_MODE_NOT_GOT = NUM_NOT_GOT, > + BOOT_MODE_AUTOSTART = 1, > + BOOT_MODE_NONE = 2 > +} BootMode; > + > +struct BR_Prop { > + int STP; > + int delay; > + char **port_names; > + int port_num; > +} ; > + > +struct Run_Prop { > + int status; > + BootMode boot_mode; > +} ; > + > +struct VLAN_Prop_8021q { > + int vlan_id; > + char *parent; > +} ; > + > +/* HP vlan standard, TBD */ > +struct VLAN_Prop_8021qbg { > + int invalid; > +} ; > + > +/* Cisco and VMware vlan standard, TBD */ > +struct VLAN_Prop_8021qbh { > + int invalid; > +} ; > + > +struct VLAN_Prop { > + int vlan_type; > + union { > + struct VLAN_Prop_8021q prop_8021q; > + struct VLAN_Prop_8021qbg prop_8021qbg; > + struct VLAN_Prop_8021qbh prop_8021qbh; > + } props; > +} ; > + > +/* EthIface is logical devices include eth ports and bridges */ > +struct EthIface { > + char *name; > + char *dep_ifname; /* parent dev name */ > + char *attach_bridge; /* bridge the iface is attached to */ > + char *mac; > + EthType eth_type; > + struct Run_Prop run_prop; > + /* optional properties */ > + struct BR_Prop *pbr_prop; > + struct VLAN_Prop *pvlan_prop; > +} ; > + > +struct EthIfacesList { > + struct EthIface *pifaces[MAX_IFACE_NUM]; > + int count; > +} ; > + > +void eth_iface_init(struct EthIface *piface); > +void eth_iface_add_br_prop(struct EthIface *piface); > +void eth_iface_add_vlan_prop(struct EthIface *piface, int vlan_type); > +void eth_iface_uninit(struct EthIface *piface); > + > +void eth_ifaceslist_init(struct EthIfacesList *plist); > +void eth_ifaceslist_uninit(struct EthIfacesList *plist); > +/* ppiface must be allocated from heap, to save code of struct duplication */ > +int eth_ifaceslist_add(struct EthIfacesList *plist, struct EthIface **ppiface); > +/* returned pointer is direct reference to a member in plist */ > +struct EthIface *eth_ifaceslist_search(struct EthIfacesList *plist, > + char *name); > + > +void eth_iface_print(struct EthIface *piface); > +void eth_ifaceslist_print(struct EthIfacesList *plist); > + > +CMPIStatus get_host_ifaces(struct EthIfacesList *plist, > + const CMPIBroker *broker, char *prefix); > + > +const char *EthIfaceListTOXML(char **ppxml, > + struct EthIfacesList *plist, > + int dump_all_flag); > + > +#endif > diff --git a/libxkutil/network_parsing_test.c b/libxkutil/network_parsing_test.c > new file mode 100644 > index 0000000..593bfd0 > --- /dev/null > +++ b/libxkutil/network_parsing_test.c > @@ -0,0 +1,61 @@ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > + > +#include "misc_util.h" > +#include "device_parsing.h" > +#include "network_parsing.h" > + > +static const CMPIBroker *broker; > + > +static long print_and_ret_time_stamp(void) > +{ > + struct timeval tv; > + long ret; > + gettimeofday(&tv, NULL); > + ret = tv.tv_sec*1000 + tv.tv_usec/1000; > + CU_DEBUG("time is [%ld] ms.", ret); > + return ret; > +} > + > +/* try retrieve all information, and then map them back to xml. */ > +int main(int argc, char **argv) > +{ > + libvirt_cim_init(); > + struct EthIfacesList *plist = NULL; > + const char *msg = NULL; > + char *genxml = NULL; > + CMPIStatus s; > + long start_time, end_time; > + > + SAFE_MALLOC(plist, sizeof(struct EthIfacesList)); > + eth_ifaceslist_init(plist); > + > + start_time = print_and_ret_time_stamp(); > + s = get_host_ifaces(plist, broker, "kvm"); > + end_time = print_and_ret_time_stamp(); > + CU_DEBUG("cost [%d]ms in discovering host network. Result:", > + end_time - start_time); > + eth_ifaceslist_print(plist); > + > + msg = EthIfaceListTOXML(&genxml, plist, 1); > + CU_DEBUG("xml gen msg is %s. xml is:\n%s", msg, genxml); > + SAFE_FREE(genxml); > + > + eth_ifaceslist_uninit(plist); > + SAFE_FREE(plist); > + return 0; > +} > diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c > index 9a2ada9..001246a 100644 > --- a/libxkutil/xmlgen.c > +++ b/libxkutil/xmlgen.c > @@ -830,7 +830,7 @@ static char *features_xml(xmlNodePtr root, struct domain *domain) > return NULL; > } > > -static char *tree_to_xml(xmlNodePtr root) > +char *tree_to_xml(xmlNodePtr root) > { > xmlBufferPtr buffer = NULL; > xmlSaveCtxtPtr savectx = NULL; > diff --git a/libxkutil/xmlgen.h b/libxkutil/xmlgen.h > index 743fc82..5d21a94 100644 > --- a/libxkutil/xmlgen.h > +++ b/libxkutil/xmlgen.h > @@ -32,6 +32,8 @@ struct kv { > const char *val; > }; > > +char *tree_to_xml(xmlNodePtr root); > + > char *system_to_xml(struct domain *dominfo); > char *device_to_xml(struct virt_device *dev); > From eblima at linux.vnet.ibm.com Thu Jan 26 19:16:58 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Thu, 26 Jan 2012 17:16:58 -0200 Subject: [Libvirt-cim] [PATCH] [TEST] WIP: Update FilterList/03_create.py Message-ID: <1327605418-27286-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" According to recent changes in FilterList provider. Note that this is still work in progress. Sending only for testing purposes. Signed-off-by: Eduardo Lima (Etrunko) --- suites/libvirt-cim/cimtest/FilterList/03_create.py | 36 ++++++++++++++++---- suites/libvirt-cim/cimtest/FilterList/helper.py | 18 +++++++++- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/suites/libvirt-cim/cimtest/FilterList/03_create.py b/suites/libvirt-cim/cimtest/FilterList/03_create.py index 157bd23..4a66f09 100644 --- a/suites/libvirt-cim/cimtest/FilterList/03_create.py +++ b/suites/libvirt-cim/cimtest/FilterList/03_create.py @@ -37,6 +37,9 @@ from VirtLib.utils import run_remote sup_types = ["KVM",] domain = None +flist_name = None +nested_name = None +applied_name = None def get_filter_inst_and_inst_name(name): try: @@ -88,6 +91,7 @@ def create_filter_list(name): # A NestedFilterList instance will add the "clean-traffic" filter # as an entry of the newly created FilterList + global nested_name logger.info("Creating NestedFilterList instance") nested_name = test.CreateFilterListInstance(None, "KVM_NestedFilterList", {"Antecedent":flist_name, @@ -124,8 +128,12 @@ def get_nwport_inst_and_inst_name(domain_name): def cleanup(): try: - # Destroy filter list - test.wbem.DeleteInstance(flist_name) + # Destroy filter list instances + for n in [applied_name, nested_name, flist_name]: + if n is not None: + logger.info("Deleting instance %s", n) + test.wbem.DeleteInstance(n) + logger.info("OK") except Exception, e: logger.error("Error deleting filter list: %s", e) @@ -164,15 +172,29 @@ def main(): # An AppliedFilterList Instance will apply the filter to the network # port of the defined domain - test.CreateFilterListInstance(None, "KVM_AppliedFilterList", - {"Antecedent":nwport_name, - "Dependent":flist_name}) + global applied_name + logger.info ("Creating AppliedFilterList instance") + applied_name = test.CreateFilterListInstance(None, "KVM_AppliedFilterList", + {"Antecedent":nwport_name, + "Dependent":flist_name}) + logger.info("Got AppliedFilterList name '%s'", applied_name) + #applied = test.GetInstance(applied_name) + #logger.info("Got AppliedFilterList '%s'", applied) + + # Check results + filterref = test.libvirt_applied_filter_lists(domain_name)[0] + rule = helper.FilterRule(filterref) + if rule.filter != test_flist: + raise Exception("AppliedFilterList name '%s' does not match expected '%s'", + rule.filter, test_flist) + + test.cim_applied_filter_lists(domain_name) + logger.info("AppliedFilterList created succesfully") + result = PASS except Exception, e: logger.error("Caught exception: %s", e) result = FAIL - # Check results - # Cleanup cleanup() diff --git a/suites/libvirt-cim/cimtest/FilterList/helper.py b/suites/libvirt-cim/cimtest/FilterList/helper.py index 294ae8f..c7e8612 100644 --- a/suites/libvirt-cim/cimtest/FilterList/helper.py +++ b/suites/libvirt-cim/cimtest/FilterList/helper.py @@ -307,6 +307,22 @@ class FilterListTest(BaseTestObject): return self.Associators(_inst_name, result_class="CIM_FilterEntryBase") # cim_entries_in_filter_list + + def libvirt_applied_filter_lists(self, dom_name): + cmd = "virsh -q -c %s dumpxml %s 2>/dev/null" % (self.uri, dom_name) + ret, dom_xml = run_remote(self.server, cmd) + if ret: + logger.error("Error retrieving domain xml for %s", dom_name) + return None + + xdoc = etree.fromstring(dom_xml) + filter_list = xdoc.xpath("/domain/devices/interface/filterref") + return filter_list + # libvirt_applied_filter_lists + + def cim_applied_filter_lists(self, dom_name): + pass + # cim_applied_filter_lists # FilterListTest @@ -394,7 +410,7 @@ class FilterRule(object): for e in element: self.__dict = dict(self.__dict, **e.attrib) - if not self.__type: + if self.__type is None: self.__type = e.tag try: -- 1.7.7.6 From cvincent at linux.vnet.ibm.com Thu Jan 26 20:01:06 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Thu, 26 Jan 2012 15:01:06 -0500 Subject: [Libvirt-cim] [PATCH v4] Fix AppliedFilterList creation and deletion Message-ID: <1327608066-21678-1-git-send-email-cvincent@linux.vnet.ibm.com> From: Chip Vincent Fixes many small issues with the current AppliedFilterList provider. 1) Fix Create to properly return a complete object path and fix Delete to properly parse that path. 2) Persist applied filer rules. Since it's not possible to dyanmically update a single device, I've changed the code to modify and re-define the VM to essentially add/remove ACL filter associations. I also updated the code to minimize domain/device parsing overhead. For some strange reason, our internal APIs sometimes take a virDomainPtr and other times a struct domain * forcing providers who work with domains *and* devices to parse everything twice. Until the internal APIs are cleaned up, I simply parse everything once and then fetch the device manually from the struct domain *. 3) Add VIR_DOMAIN_XML_INACTIVE to virDomainGetXML(). By default, libvirt only returns the XML of the running domain. We need to fetch the *stored* XML that will be used for the next boot so that all changes made while the VM is running are preserved. Changes from v3: - Fix NestedFilterList DeleteInstance - Fix remove_filter_ref() in acl_parsing.c (intend to refactor in future patch) Changes from v2: - Return the correct reference in NestedFilterList Changes from v1: - Fix leak and other comments - Fix all cases virDomainGetXML() - Fix NestedFilterList Create/Delete instance Signed-off-by: Chip Vincent --- libxkutil/acl_parsing.c | 1 + libxkutil/device_parsing.c | 6 ++- src/Virt_AppliedFilterList.c | 97 +++++++++++++++++++---------------- src/Virt_ComputerSystem.c | 3 +- src/Virt_ComputerSystemIndication.c | 3 +- src/Virt_FilterList.c | 5 ++- src/Virt_NestedFilterList.c | 19 +++++-- src/Virt_VSMigrationService.c | 3 +- 8 files changed, 82 insertions(+), 55 deletions(-) diff --git a/libxkutil/acl_parsing.c b/libxkutil/acl_parsing.c index 5b6d7bb..9c4b4b2 100644 --- a/libxkutil/acl_parsing.c +++ b/libxkutil/acl_parsing.c @@ -652,6 +652,7 @@ int remove_filter_ref(struct acl_filter *filter, const char *name) /* TODO: called infrequently, but needs optimization */ old_refs = filter->refs; + filter->ref_ct = 0; for (i = 0; i < filter->ref_ct; i++) { if (STREQC(old_refs[i], name)) { diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c index a1e8d6c..ff86f2a 100644 --- a/libxkutil/device_parsing.c +++ b/libxkutil/device_parsing.c @@ -996,7 +996,8 @@ int get_devices(virDomainPtr dom, struct virt_device **list, int type) char *xml; int ret; - xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_SECURE); + xml = virDomainGetXMLDesc(dom, + VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); if (xml == NULL) return 0; @@ -1241,7 +1242,8 @@ int get_dominfo(virDomainPtr dom, struct domain **dominfo) char *xml; int ret; int start; - xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_SECURE); + xml = virDomainGetXMLDesc(dom, + VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); if (xml == NULL) return 0; diff --git a/src/Virt_AppliedFilterList.c b/src/Virt_AppliedFilterList.c index bc31c14..538adf4 100644 --- a/src/Virt_AppliedFilterList.c +++ b/src/Virt_AppliedFilterList.c @@ -97,67 +97,60 @@ static CMPIrc cu_get_ref_path(const CMPIObjectPath *reference, if ((s.rc != CMPI_RC_OK) || CMIsNullValue(value)) return CMPI_RC_ERR_NO_SUCH_PROPERTY; - /* how to parse and object path? */ + if ((value.type != CMPI_ref) || CMIsNullObject(value.value.ref)) + return CMPI_RC_ERR_TYPE_MISMATCH; + + *_reference = value.value.ref; return CMPI_RC_OK; } -/* TODO: Port to libxkutil/device_parsing.c */ -static int update_device(virDomainPtr dom, - struct virt_device *dev) +static int update_domain(virConnectPtr conn, + struct domain *dominfo) { -#if LIBVIR_VERSION_NUMBER > 8000 char *xml = NULL; - int flags = VIR_DOMAIN_DEVICE_MODIFY_CURRENT | - VIR_DOMAIN_DEVICE_MODIFY_CONFIG; - int ret = 0; + virDomainPtr dom = NULL; - xml = device_to_xml(dev); + xml = system_to_xml(dominfo); if (xml == NULL) { - CU_DEBUG("Failed to get XML for device '%s'", dev->id); + CU_DEBUG("Failed to get XML from domain %s", dominfo->name); goto out; } - if (virDomainUpdateDeviceFlags(dom, xml, flags) != 0) { - CU_DEBUG("Failed to dynamically update device"); + dom = virDomainDefineXML(conn, xml); + if (dom == NULL) { + CU_DEBUG("Failed to update domain %s", dominfo->name); goto out; } - ret = 1; out: free(xml); + virDomainFree(dom); - return ret; -#else return 0; -#endif } -/* TODO: Port to libxkutil/device_parsing.c */ -static int get_device_by_devid(virDomainPtr dom, +static int get_device_by_devid(struct domain *dominfo, const char *devid, - int type, struct virt_device **dev) { - int i, ret = 0; - struct virt_device *devices = NULL; - int count = get_devices(dom, &devices, type); + int i; + struct virt_device *devices = dominfo->dev_net; + int count = dominfo->dev_net_ct; + + if (dev == NULL) + return 0; for (i = 0; i < count; i++) { if (STREQC(devid, devices[i].id)) { CU_DEBUG("Found '%s'", devices[i].id); - *dev = virt_device_dup(&devices[i]); - if (*dev != NULL) - ret = 1; - - break; + *dev = &devices[i]; + return 0; } } - cleanup_virt_devices(&devices, count); - - return ret; + return 1; } /** @@ -425,6 +418,8 @@ static CMPIStatus CreateInstance( struct virt_device *device = NULL; virConnectPtr conn = NULL; virDomainPtr dom = NULL; + struct domain *dominfo = NULL; + CMPIObjectPath *_reference = NULL; conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s); if (conn == NULL) @@ -487,8 +482,12 @@ static CMPIStatus CreateInstance( goto out; } - get_device_by_devid(dom, net_name, CIM_RES_TYPE_NET, &device); - if (device == NULL) { + if (get_dominfo(dom, &dominfo) == 0) { + CU_DEBUG("Failed to get dominfo"); + goto out; + } + + if (get_device_by_devid(dominfo, net_name, &device) != 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, "Dependent.Name object does not exist"); @@ -502,14 +501,19 @@ static CMPIStatus CreateInstance( device->dev.net.filter_ref = strdup(filter_name); - if (update_device(dom, device) == 0) { + if (update_domain(conn, dominfo) != 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, - "Failed to update device"); + "Failed to update domain"); goto out; } - CMReturnObjectPath(results, reference); + /* create new object path */ + _reference = CMClone(reference, NULL); + CMAddKey(_reference, "Antecedent", (CMPIValue *)&antecedent, CMPI_ref); + CMAddKey(_reference, "Dependent", (CMPIValue *)&dependent, CMPI_ref); + + CMReturnObjectPath(results, _reference); CU_DEBUG("CreateInstance complete"); out: @@ -542,6 +546,7 @@ static CMPIStatus DeleteInstance( struct virt_device *device = NULL; virConnectPtr conn = NULL; virDomainPtr dom = NULL; + struct domain *dominfo = NULL; conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s); if (conn == NULL) @@ -557,7 +562,7 @@ static CMPIStatus DeleteInstance( goto out; } - if (cu_get_str_path(reference, "DeviceID", + if (cu_get_str_path(antecedent, "DeviceID", &device_name) != CMPI_RC_OK) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, @@ -573,7 +578,7 @@ static CMPIStatus DeleteInstance( goto out; } - if (cu_get_str_path(reference, "Name", + if (cu_get_str_path(dependent, "Name", &filter_name) != CMPI_RC_OK) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, @@ -585,7 +590,7 @@ static CMPIStatus DeleteInstance( if (filter == NULL) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, - "Antecedent.Name object does not exist"); + "Dependent.Name object does not exist"); goto out; } @@ -600,11 +605,15 @@ static CMPIStatus DeleteInstance( goto out; } - get_device_by_devid(dom, net_name, CIM_RES_TYPE_NET, &device); - if (device == NULL) { + if (get_dominfo(dom, &dominfo) == 0) { + CU_DEBUG("Failed to get dominfo"); + goto out; + } + + if (get_device_by_devid(dominfo, net_name, &device) != 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, - "Dependent.Name object does not exist"); + "Antecedent.Name object does not exist"); goto out; } @@ -613,14 +622,14 @@ static CMPIStatus DeleteInstance( device->dev.net.filter_ref = NULL; } - if (update_device(dom, device) == 0) { + if (update_domain(conn, dominfo) != 0) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, - "Failed to update device"); + "Failed to update domain"); goto out; } - CU_DEBUG("CreateInstance complete"); + CU_DEBUG("DeleteInstance complete"); out: free(domain_name); diff --git a/src/Virt_ComputerSystem.c b/src/Virt_ComputerSystem.c index 582253a..e6c7e55 100644 --- a/src/Virt_ComputerSystem.c +++ b/src/Virt_ComputerSystem.c @@ -926,7 +926,8 @@ static CMPIStatus domain_reset(virDomainPtr dom) return s; } - xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_SECURE); + xml = virDomainGetXMLDesc(dom, + VIR_DOMAIN_XML_INACTIVE |VIR_DOMAIN_XML_SECURE); if (xml == NULL) { CU_DEBUG("Unable to retrieve domain XML"); virt_set_status(_BROKER, &s, diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c index eb1a71c..6ef2ddc 100644 --- a/src/Virt_ComputerSystemIndication.c +++ b/src/Virt_ComputerSystemIndication.c @@ -107,7 +107,8 @@ static int csi_dom_xml_set(csi_dom_xml_t *dom, virDomainPtr dom_ptr, CMPIStatus dom->name = strdup(name); /* xml */ - dom->xml = virDomainGetXMLDesc(dom_ptr, VIR_DOMAIN_XML_SECURE); + dom->xml = virDomainGetXMLDesc(dom_ptr, + VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); if (dom->xml == NULL) { cu_statusf(_BROKER, s, CMPI_RC_ERR_FAILED, diff --git a/src/Virt_FilterList.c b/src/Virt_FilterList.c index 35d18a9..5b1b6e8 100644 --- a/src/Virt_FilterList.c +++ b/src/Virt_FilterList.c @@ -358,7 +358,10 @@ static CMPIStatus DeleteInstance( goto out; } - delete_filter(conn, filter); + if (delete_filter(conn, filter) != 0) { + CU_DEBUG("Failed to delete filter %s", filter->name); + goto out; + } out: cleanup_filters(&filter, 1); diff --git a/src/Virt_NestedFilterList.c b/src/Virt_NestedFilterList.c index 894cd7c..81c4408 100644 --- a/src/Virt_NestedFilterList.c +++ b/src/Virt_NestedFilterList.c @@ -98,7 +98,10 @@ static CMPIrc cu_get_ref_path(const CMPIObjectPath *reference, if ((s.rc != CMPI_RC_OK) || CMIsNullValue(value)) return CMPI_RC_ERR_NO_SUCH_PROPERTY; - /* how to parse and object path? */ + if ((value.type != CMPI_ref) || CMIsNullObject(value.value.ref)) + return CMPI_RC_ERR_TYPE_MISMATCH; + + *_reference = value.value.ref; return CMPI_RC_OK; } @@ -305,6 +308,7 @@ static CMPIStatus CreateInstance( const char *child_name = NULL; struct acl_filter *child_filter = NULL; virConnectPtr conn = NULL; + CMPIObjectPath *_reference = NULL; CU_DEBUG("Reference = %s", REF2STR(reference)); @@ -383,7 +387,12 @@ static CMPIStatus CreateInstance( goto out; } - CMReturnObjectPath(results, reference); + /* create new object path */ + _reference = CMClone(reference, NULL); + CMAddKey(_reference, "Antecedent", (CMPIValue *)&antecedent, CMPI_ref); + CMAddKey(_reference, "Dependent", (CMPIValue *)&dependent, CMPI_ref); + + CMReturnObjectPath(results, _reference); CU_DEBUG("CreateInstance completed"); out: @@ -423,7 +432,7 @@ static CMPIStatus DeleteInstance( goto out; } - if (cu_get_str_path(reference, "Name", &parent_name) != CMPI_RC_OK) { + if (cu_get_str_path(antecedent, "Name", &parent_name) != CMPI_RC_OK) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, "Unable to get Antecedent.Name property"); @@ -446,7 +455,7 @@ static CMPIStatus DeleteInstance( goto out; } - if (cu_get_str_path(reference, "Name", &child_name) != CMPI_RC_OK) { + if (cu_get_str_path(dependent, "Name", &child_name) != CMPI_RC_OK) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, "Unable to get Dependent.Name property"); @@ -475,7 +484,7 @@ static CMPIStatus DeleteInstance( goto out; } - CU_DEBUG("CreateInstance completed"); + CU_DEBUG("DeleteInstance completed"); out: cleanup_filters(&parent_filter, 1); diff --git a/src/Virt_VSMigrationService.c b/src/Virt_VSMigrationService.c index d393787..76e3d25 100644 --- a/src/Virt_VSMigrationService.c +++ b/src/Virt_VSMigrationService.c @@ -1070,7 +1070,8 @@ static CMPIStatus prepare_migrate(virDomainPtr dom, { CMPIStatus s = {CMPI_RC_OK, NULL}; - *xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_SECURE); + *xml = virDomainGetXMLDesc(dom, + VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); if (*xml == NULL) { virt_set_status(_BROKER, &s, -- 1.7.1 From cvincent at linux.vnet.ibm.com Thu Jan 26 20:02:29 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Thu, 26 Jan 2012 15:02:29 -0500 Subject: [Libvirt-cim] [PATCH] [TEST] WIP: Update FilterList/03_create.py In-Reply-To: <1327605418-27286-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1327605418-27286-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F21B155.8040506@linux.vnet.ibm.com> Thanks. This helped me find the problem. Fix for NestedFilterList is in v4 patch. BTW - On RHEL 6.2, I'm seeing the follow message periodically when I run with this cimtest patch. /home/cvincent/proj/cimtest/suites/libvirt-cim/cimtest/FilterList/helper.py:255: FutureWarning: The behavior of this method will change in future versions. Use specific 'len(elem)' or 'elem is not None' test instead. if not root: On 01/26/2012 02:16 PM, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > According to recent changes in FilterList provider. > > Note that this is still work in progress. Sending only for testing purposes. > > Signed-off-by: Eduardo Lima (Etrunko) > --- > suites/libvirt-cim/cimtest/FilterList/03_create.py | 36 ++++++++++++++++---- > suites/libvirt-cim/cimtest/FilterList/helper.py | 18 +++++++++- > 2 files changed, 46 insertions(+), 8 deletions(-) > > diff --git a/suites/libvirt-cim/cimtest/FilterList/03_create.py b/suites/libvirt-cim/cimtest/FilterList/03_create.py > index 157bd23..4a66f09 100644 > --- a/suites/libvirt-cim/cimtest/FilterList/03_create.py > +++ b/suites/libvirt-cim/cimtest/FilterList/03_create.py > @@ -37,6 +37,9 @@ from VirtLib.utils import run_remote > sup_types = ["KVM",] > > domain = None > +flist_name = None > +nested_name = None > +applied_name = None > > def get_filter_inst_and_inst_name(name): > try: > @@ -88,6 +91,7 @@ def create_filter_list(name): > > # A NestedFilterList instance will add the "clean-traffic" filter > # as an entry of the newly created FilterList > + global nested_name > logger.info("Creating NestedFilterList instance") > nested_name = test.CreateFilterListInstance(None, "KVM_NestedFilterList", > {"Antecedent":flist_name, > @@ -124,8 +128,12 @@ def get_nwport_inst_and_inst_name(domain_name): > > def cleanup(): > try: > - # Destroy filter list > - test.wbem.DeleteInstance(flist_name) > + # Destroy filter list instances > + for n in [applied_name, nested_name, flist_name]: > + if n is not None: > + logger.info("Deleting instance %s", n) > + test.wbem.DeleteInstance(n) > + logger.info("OK") > except Exception, e: > logger.error("Error deleting filter list: %s", e) > > @@ -164,15 +172,29 @@ def main(): > > # An AppliedFilterList Instance will apply the filter to the network > # port of the defined domain > - test.CreateFilterListInstance(None, "KVM_AppliedFilterList", > - {"Antecedent":nwport_name, > - "Dependent":flist_name}) > + global applied_name > + logger.info ("Creating AppliedFilterList instance") > + applied_name = test.CreateFilterListInstance(None, "KVM_AppliedFilterList", > + {"Antecedent":nwport_name, > + "Dependent":flist_name}) > + logger.info("Got AppliedFilterList name '%s'", applied_name) > + #applied = test.GetInstance(applied_name) > + #logger.info("Got AppliedFilterList '%s'", applied) > + > + # Check results > + filterref = test.libvirt_applied_filter_lists(domain_name)[0] > + rule = helper.FilterRule(filterref) > + if rule.filter != test_flist: > + raise Exception("AppliedFilterList name '%s' does not match expected '%s'", > + rule.filter, test_flist) > + > + test.cim_applied_filter_lists(domain_name) > + logger.info("AppliedFilterList created succesfully") > + result = PASS > except Exception, e: > logger.error("Caught exception: %s", e) > result = FAIL > > - # Check results > - > # Cleanup > cleanup() > > diff --git a/suites/libvirt-cim/cimtest/FilterList/helper.py b/suites/libvirt-cim/cimtest/FilterList/helper.py > index 294ae8f..c7e8612 100644 > --- a/suites/libvirt-cim/cimtest/FilterList/helper.py > +++ b/suites/libvirt-cim/cimtest/FilterList/helper.py > @@ -307,6 +307,22 @@ class FilterListTest(BaseTestObject): > > return self.Associators(_inst_name, result_class="CIM_FilterEntryBase") > # cim_entries_in_filter_list > + > + def libvirt_applied_filter_lists(self, dom_name): > + cmd = "virsh -q -c %s dumpxml %s 2>/dev/null" % (self.uri, dom_name) > + ret, dom_xml = run_remote(self.server, cmd) > + if ret: > + logger.error("Error retrieving domain xml for %s", dom_name) > + return None > + > + xdoc = etree.fromstring(dom_xml) > + filter_list = xdoc.xpath("/domain/devices/interface/filterref") > + return filter_list > + # libvirt_applied_filter_lists > + > + def cim_applied_filter_lists(self, dom_name): > + pass > + # cim_applied_filter_lists > # FilterListTest > > > @@ -394,7 +410,7 @@ class FilterRule(object): > > for e in element: > self.__dict = dict(self.__dict, **e.attrib) > - if not self.__type: > + if self.__type is None: > self.__type = e.tag > > try: -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From eblima at linux.vnet.ibm.com Fri Jan 27 12:08:36 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 27 Jan 2012 10:08:36 -0200 Subject: [Libvirt-cim] [PATCH] [TEST] WIP: Update FilterList/03_create.py In-Reply-To: <4F21B155.8040506@linux.vnet.ibm.com> References: <1327605418-27286-1-git-send-email-eblima@linux.vnet.ibm.com> <4F21B155.8040506@linux.vnet.ibm.com> Message-ID: <4F2293C4.1030003@linux.vnet.ibm.com> On 01/26/2012 06:02 PM, Chip Vincent wrote: > Thanks. This helped me find the problem. Fix for NestedFilterList is in > v4 patch. Good news. :) I just saw the patch and will test right now. > BTW - On RHEL 6.2, I'm seeing the follow message periodically when I run > with this cimtest patch. > > /home/cvincent/proj/cimtest/suites/libvirt-cim/cimtest/FilterList/helper.py:255: > FutureWarning: The behavior of this method will change in future > versions. Use specific 'len(elem)' or 'elem is not None' test instead. > if not root: > Yep, this fix is in a patch in my private tree. I will include it in this patch. -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Fri Jan 27 12:21:29 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Fri, 27 Jan 2012 10:21:29 -0200 Subject: [Libvirt-cim] [PATCH v4] Fix AppliedFilterList creation and deletion In-Reply-To: <1327608066-21678-1-git-send-email-cvincent@linux.vnet.ibm.com> References: <1327608066-21678-1-git-send-email-cvincent@linux.vnet.ibm.com> Message-ID: <4F2296C9.6040207@linux.vnet.ibm.com> On 01/26/2012 06:01 PM, Chip Vincent wrote: > From: Chip Vincent > > Fixes many small issues with the current AppliedFilterList provider. > > 1) Fix Create to properly return a complete object path and fix Delete to > properly parse that path. > > 2) Persist applied filer rules. Since it's not possible to dyanmically update > a single device, I've changed the code to modify and re-define the VM to > essentially add/remove ACL filter associations. > > I also updated the code to minimize domain/device parsing overhead. For > some strange reason, our internal APIs sometimes take a virDomainPtr and > other times a struct domain * forcing providers who work with domains > *and* devices to parse everything twice. Until the internal APIs are > cleaned up, I simply parse everything once and then fetch the device > manually from the struct domain *. > > 3) Add VIR_DOMAIN_XML_INACTIVE to virDomainGetXML(). By default, libvirt only > returns the XML of the running domain. We need to fetch the *stored* XML > that will be used for the next boot so that all changes made while the VM > is running are preserved. > > Changes from v3: > - Fix NestedFilterList DeleteInstance > - Fix remove_filter_ref() in acl_parsing.c (intend to refactor in > future patch) > +1. Yay, tests passed without crashing. :) I'll finish the cimtest patch and submit to the list. -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From cvincent at linux.vnet.ibm.com Fri Jan 27 13:08:31 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Fri, 27 Jan 2012 08:08:31 -0500 Subject: [Libvirt-cim] [PATCH v4] Fix AppliedFilterList creation and deletion In-Reply-To: <4F2296C9.6040207@linux.vnet.ibm.com> References: <1327608066-21678-1-git-send-email-cvincent@linux.vnet.ibm.com> <4F2296C9.6040207@linux.vnet.ibm.com> Message-ID: <4F22A1CF.8080801@linux.vnet.ibm.com> Thanks. Pushed. On 01/27/2012 07:21 AM, Eduardo Lima (Etrunko) wrote: > On 01/26/2012 06:01 PM, Chip Vincent wrote: >> From: Chip Vincent >> >> Fixes many small issues with the current AppliedFilterList provider. >> >> 1) Fix Create to properly return a complete object path and fix Delete to >> properly parse that path. >> >> 2) Persist applied filer rules. Since it's not possible to dyanmically update >> a single device, I've changed the code to modify and re-define the VM to >> essentially add/remove ACL filter associations. >> >> I also updated the code to minimize domain/device parsing overhead. For >> some strange reason, our internal APIs sometimes take a virDomainPtr and >> other times a struct domain * forcing providers who work with domains >> *and* devices to parse everything twice. Until the internal APIs are >> cleaned up, I simply parse everything once and then fetch the device >> manually from the struct domain *. >> >> 3) Add VIR_DOMAIN_XML_INACTIVE to virDomainGetXML(). By default, libvirt only >> returns the XML of the running domain. We need to fetch the *stored* XML >> that will be used for the next boot so that all changes made while the VM >> is running are preserved. >> >> Changes from v3: >> - Fix NestedFilterList DeleteInstance >> - Fix remove_filter_ref() in acl_parsing.c (intend to refactor in >> future patch) >> > +1. Yay, tests passed without crashing. :) I'll finish the cimtest patch > and submit to the list. > -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From cvincent at linux.vnet.ibm.com Fri Jan 27 13:17:47 2012 From: cvincent at linux.vnet.ibm.com (Chip Vincent) Date: Fri, 27 Jan 2012 08:17:47 -0500 Subject: [Libvirt-cim] Freeze for release 0.6.1 Message-ID: <4F22A3FB.50104@linux.vnet.ibm.com> We are now entering the freeze for libvirt-cim-0.6.1. The plan is to spend the next week testing and fix anything needed for cimtest to pass. My testing will focus on libvirt-0.9.4+, but I welcome input from any version. I've added the tag 'release_0_6_1_candidate' so you can download and test the release candidate over the next week. Thanks, -- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent at linux.vnet.ibm.com From xiaxia347work at 163.com Fri Jan 27 13:53:26 2012 From: xiaxia347work at 163.com (xiaxia347work) Date: Fri, 27 Jan 2012 21:53:26 +0800 Subject: [Libvirt-cim] [PATCH v5] vlan extention - add function library for readonly usage In-Reply-To: <4F20948D.2040802@linux.vnet.ibm.com> References: <1327521897-17291-1-git-send-email-xiaxia347work@163.com><4F20948D.2040802@linux.vnet.ibm.com> Message-ID: <381267c1.3223.1351f7159f7.Coremail.xiaxia347work@163.com> ? 2012-1-26 7:47, Chip Vincent ??: > Thank you for the quick turnaround. The patch applied and built with no issues. Overall, I think the patch looks great. See my comments in-line. > > Test program: > NOTE: I had to remove an existing installation of libvirt-cim, use make rpm, and install an rpm with this change to get the test program to work. Otherwise, the problem would link to the wrong version of libxkutil or not properly find it. So, just updating the rpm was the quickest way to test. > I think the problem is caused by loader by default to load libxkutil.so in /usr/lib64 which need to be updated to contain the new binary code. > $ sudo CU_DEBUG=stdout .libs/network_parsing_test > .libs/network_parsing_test: symbol lookup error: .libs/network_parsing_test: undefined symbol: eth_ifaceslist_init > > For reference, I'm using RHEL 6.2. > # rpm -qa | grep libvirt > libvirt-devel-0.9.4-23.el6_2.1.x86_64 > libvirt-0.9.4-23.el6_2.1.x86_64 > libvirt-cim-0.6.0-1.el6.x86_64 > > Here's the output on my system: > network_parsing_test.c(30): time is [1327531475773] ms. > misc_util.c(168): Connecting to libvirt with uri `qemu:///system' > misc_util.c(130): 'readonly' not found in config file, assuming false > > network_parsing.c(593): 0 defined ifaces found from libvirt API. > > network_parsing.c(630): 1 active ifaces found from libvirt API. > > network_parsing.c(642): active interface 0 xml: > > > > > > > > network_parsing_test.c(30): time is [1327531475831] ms. > network_parsing_test.c(51): cost [58]ms in discovering host network. Result: > Have 1 ifaces in the list: > 0000 Iface device: name lo. > --Main Props: parent (null), attach to (null), mac (null), status 1, boot_mode 1, iface type 0x100. > network_parsing_test.c(55): xml gen msg is (null). xml is: > > > > > > > This matches the output I get with either netcf or virsh. > > On 01/25/2012 03:04 PM, xiaxia347work at 163.com wrote: >> From: Wenchao Xia >> >> This patch contain 1 test program and 1 c file doing xml and structure >> mapping. It expose some API to translate xml to device structure, in a similar >> way to code in device_parsing.c. Also some other files are changed to let new >> code use their internal functions. Type following Command in libxkutil >> directory: >> sudo CU_DEBUG=stdout .libs/network_parsing_test >> could see what it have done. >> >> v5: calling libvirt API which employ netcf instead of using libnl. From git log >> these API are available since 0.9.2, and this patch is tested with libvirt >> 0.9.4. >> >> Signed-off-by: Wenchao Xia >> --- >> libxkutil/Makefile.am | 12 +- >> libxkutil/misc_util.c | 10 +- >> libxkutil/network_parsing.c | 665 ++++++++++++++++++++++++++++++++++++++ >> libxkutil/network_parsing.h | 160 +++++++++ >> libxkutil/network_parsing_test.c | 61 ++++ >> libxkutil/xmlgen.c | 2 +- >> libxkutil/xmlgen.h | 2 + >> 7 files changed, 906 insertions(+), 6 deletions(-) >> create mode 100644 libxkutil/network_parsing.c >> create mode 100644 libxkutil/network_parsing.h >> create mode 100644 libxkutil/network_parsing_test.c >> >> diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am >> index f1adc03..c0e62eb 100644 >> --- a/libxkutil/Makefile.am >> +++ b/libxkutil/Makefile.am >> @@ -4,12 +4,14 @@ AM_CFLAGS = $(CFLAGS_STRICT) \ >> -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" >> >> noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ >> - pool_parsing.h acl_parsing.h >> + pool_parsing.h acl_parsing.h \ >> + network_parsing.h >> >> lib_LTLIBRARIES = libxkutil.la >> >> libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ >> - xmlgen.c infostore.c pool_parsing.c acl_parsing.c >> + xmlgen.c infostore.c pool_parsing.c acl_parsing.c \ >> + network_parsing.c >> libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ >> libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ >> @LIBUUID_LIBS@ >> @@ -19,3 +21,9 @@ noinst_PROGRAMS = xml_parse_test >> xml_parse_test_SOURCES = xml_parse_test.c >> xml_parse_test_LDADD = libxkutil.la \ >> @LIBVIRT_LIBS@ >> + >> +noinst_PROGRAMS += network_parsing_test >> + >> +network_parsing_test_SOURCES = network_parsing_test.c >> +network_parsing_test_LDADD = libxkutil.la \ >> + @LIBVIRT_LIBS@ >> diff --git a/libxkutil/misc_util.c b/libxkutil/misc_util.c >> index 61893c3..1c18c33 100644 >> --- a/libxkutil/misc_util.c >> +++ b/libxkutil/misc_util.c >> @@ -152,9 +152,13 @@ virConnectPtr connect_by_classname(const CMPIBroker *broker, >> >> uri = cn_to_uri(classname); >> if (!uri) { >> - cu_statusf(broker, s, >> - CMPI_RC_ERR_FAILED, >> - "Unable to generate URI from classname"); >> + if (broker) { >> + cu_statusf(broker, s, >> + CMPI_RC_ERR_FAILED, >> + "Unable to generate URI from classname"); >> + } >> + CU_DEBUG("Unable to generate URI from classname," >> + " uri is %s.", uri); >> return NULL; >> } >> >> diff --git a/libxkutil/network_parsing.c b/libxkutil/network_parsing.c >> new file mode 100644 >> index 0000000..932000c >> --- /dev/null >> +++ b/libxkutil/network_parsing.c >> @@ -0,0 +1,665 @@ >> +/* >> + * Copyright IBM Corp. 2012 >> + * >> + * Authors: >> + * Wenchao Xia >> + * >> + * This library is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU Lesser General Public >> + * License as published by the Free Software Foundation; either >> + * version 2.1 of the License, or (at your option) any later version. >> + * >> + * This library is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >> + * Lesser General Public License for more details. >> + * >> + * You should have received a copy of the GNU Lesser General Public >> + * License along with this library; if not, write to the Free Software >> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA >> + */ >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include "misc_util.h" >> +#include "xmlgen.h" >> +#include "device_parsing.h" >> +#include "network_parsing.h" >> + >> +#define XML_ERROR "Failed to allocate XML memory" > I see this is dup'd from xmlgen.c. Perhaps we should just move it to xmlgen.h so everyone can share? ok, let the codes share one define. >> + >> +static void vlan_prop_print(struct VLAN_Prop *pvlan_prop) >> +{ >> + struct VLAN_Prop_8021q *p_8021q; >> + CMD_DEBUG(1, "--VLAN props: type %d.\n", >> + pvlan_prop->vlan_type); >> + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { >> + p_8021q =&(pvlan_prop->props.prop_8021q); >> + CMD_DEBUG(1, "----IEEE802.1.Q: id %d, parent %s.\n", >> + p_8021q->vlan_id, p_8021q->parent); >> + } >> +} >> + >> +static void br_prop_print(struct BR_Prop *pbr_prop) >> +{ >> + int i = 0; >> + CMD_DEBUG(1, "--Bridge props: stp %d, delay %d, port_num %d.\n", >> + pbr_prop->STP, pbr_prop->delay, pbr_prop->port_num); >> + if (pbr_prop->port_names != NULL) { >> + CMD_DEBUG(1, "----Ports attached: "); >> + while (i< pbr_prop->port_num) { >> + CMD_DEBUG(1, " %s,", *(pbr_prop->port_names+i)); >> + i++; >> + } >> + CMD_DEBUG(1, "\n"); >> + } >> +} >> + >> +void eth_iface_print(struct EthIface *piface) >> +{ >> + CMD_DEBUG(1, "Iface device: name %s.\n" >> + "--Main Props: parent %s, attach to %s, mac %s," >> + " status %d, boot_mode %d, iface type 0x%x.\n", >> + piface->name, piface->dep_ifname, piface->attach_bridge, >> + piface->mac, >> + piface->run_prop.status, piface->run_prop.boot_mode, piface->eth_type); >> + if (piface->pbr_prop != NULL) { >> + br_prop_print(piface->pbr_prop); >> + } >> + if (piface->pvlan_prop != NULL) { >> + vlan_prop_print(piface->pvlan_prop); >> + } >> + return; >> +} >> + >> +void eth_ifaceslist_print(struct EthIfacesList *plist) >> +{ >> + int i = 0; >> + CMD_DEBUG(1, "Have %d ifaces in the list:\n", plist->count); >> + while (i< plist->count) { >> + CMD_DEBUG(1, "%04d ", i); >> + eth_iface_print(plist->pifaces[i]); >> + i++; >> + } >> +} >> + >> +static void vlan_prop_init(struct VLAN_Prop *pvlan_prop, int vlan_type) >> +{ >> + struct VLAN_Prop_8021q *p_8021q; >> + memset(pvlan_prop, 0, sizeof(struct VLAN_Prop)); >> + pvlan_prop->vlan_type = vlan_type; >> + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { >> + p_8021q =&(pvlan_prop->props.prop_8021q); >> + p_8021q->vlan_id = NUM_NOT_GOT; >> + } >> +} >> + >> +static void br_prop_init(struct BR_Prop *pbr_prop) >> +{ >> + memset(pbr_prop, 0, sizeof(struct BR_Prop)); >> + pbr_prop->STP = NUM_NOT_GOT; >> + pbr_prop->delay = NUM_NOT_GOT; >> + pbr_prop->port_num = NUM_NOT_GOT; >> +} >> + >> +void eth_iface_init(struct EthIface *piface) >> +{ >> + memset(piface, 0, sizeof(struct EthIface)); >> + piface->eth_type = ETH_TYPE_NOT_GOT; >> + piface->run_prop.status = NUM_NOT_GOT; >> + piface->run_prop.boot_mode = BOOT_MODE_NOT_GOT; >> + return; >> +} >> + >> +void eth_iface_add_br_prop(struct EthIface *piface) >> +{ >> + if (piface->pbr_prop != NULL) { >> + return; >> + } >> + SAFE_MALLOC(piface->pbr_prop, sizeof(struct BR_Prop)); >> + br_prop_init(piface->pbr_prop); >> +} >> + >> +void eth_iface_add_vlan_prop(struct EthIface *piface, int vlan_type) >> +{ >> + if (piface->pvlan_prop != NULL) { >> + return; >> + } > Indent above sorry missed it. >> + SAFE_MALLOC(piface->pvlan_prop, sizeof(struct VLAN_Prop)); >> + vlan_prop_init(piface->pvlan_prop, vlan_type); >> +} >> + >> +static void vlan_prop_uninit(struct VLAN_Prop *pvlan_prop) >> +{ >> + struct VLAN_Prop_8021q *p_8021q; >> + if (pvlan_prop == NULL) { >> + return; >> + } >> + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { >> + p_8021q =&(pvlan_prop->props.prop_8021q); >> + SAFE_FREE(p_8021q->parent); >> + } >> +} >> + >> +static void br_prop_uninit(struct BR_Prop *pbr_prop) >> +{ >> + int i; >> + if (pbr_prop == NULL) { >> + return; >> + } >> + i = 0; > why not init i when defined? ok. >> + if (pbr_prop->port_names != NULL) { >> + while (i< pbr_prop->port_num) { >> + SAFE_FREE(pbr_prop->port_names[i]); >> + i++; >> + } >> + SAFE_FREE(pbr_prop->port_names); >> + } >> +} >> + >> +void eth_iface_uninit(struct EthIface *piface) >> +{ >> + if (piface == NULL) { >> + return; >> + } >> + SAFE_FREE(piface->name); >> + SAFE_FREE(piface->dep_ifname); >> + SAFE_FREE(piface->attach_bridge); >> + SAFE_FREE(piface->mac); >> + br_prop_uninit(piface->pbr_prop); >> + SAFE_FREE(piface->pbr_prop); >> + vlan_prop_uninit(piface->pvlan_prop); >> + SAFE_FREE(piface->pvlan_prop); >> + return; >> +} >> + >> +void eth_ifaceslist_init(struct EthIfacesList *plist) >> +{ >> + plist->count = 0; >> +} >> + >> +void eth_ifaceslist_uninit(struct EthIfacesList *plist) >> +{ >> + struct EthIface **t; >> + int i; > init variable to 0 or NULL ok. >> + if (plist->count<= 0) { >> + return; >> + } >> + t = plist->pifaces; >> + i = 0; >> + while (i< plist->count) { >> + if (*t != NULL) { >> + eth_iface_uninit(*t); >> + SAFE_FREE(*t); >> + } >> + t++; >> + i++; >> + } >> + return; >> +} >> + >> +int eth_ifaceslist_add(struct EthIfacesList *plist, struct EthIface **ppiface) >> +{ >> + if (plist->count>= MAX_IFACE_NUM) { >> + CU_DEBUG("too much device found."); >> + return 0; >> + } >> + plist->pifaces[plist->count] = *ppiface; >> + *ppiface = NULL; >> + plist->count++; >> + return 1; >> +} >> + >> +struct EthIface *eth_ifaceslist_search(struct EthIfacesList *plist, >> + char *name) >> +{ >> + int i = 0; >> + struct EthIface *piface = NULL; >> + >> + while (i< plist->count) { >> + piface = plist->pifaces[i]; >> + i++; >> + if (piface != NULL) { >> + if (0 == strcmp(piface->name, name)) { >> + return piface; >> + } >> + } >> + } >> + return NULL; >> +} >> + >> +/* Dummy function to suppress error message from libxml2 */ >> +static void swallow_err_msg(void *ctx, const char *msg, ...) >> +{ >> + /* do nothing, just swallow the message. */ >> +} >> + >> + >> +static const char *gen_eth_xmlnode_iface(xmlNodePtr root, >> + struct EthIface *piface, >> + struct EthIfacesList *plist, >> + int bridge_port_flag) >> +{ >> + const char *msg = NULL; >> + xmlNodePtr temp_node1 = NULL, temp_node2 = NULL, temp_node3 = NULL; >> + char *str, buf[16]; >> + int i; >> + struct EthIface *pifaceport; > By convention, we try to init all pointers. >> + >> + if (piface->name == NULL) { >> + msg = "iface have no name.\n"; >> + goto out; >> + } >> + /* netcfg have no xml for iface attatched to bridge */ > s/have/has/ I tried the netcf in virt-manager, if one eth is attached to a bridge, then the eth have no "standalone" xml, but a embbed one in the bridge. it is something like following: >> + if ((piface->attach_bridge != NULL)&& (bridge_port_flag != 1)) { >> + goto out; >> + } >> + >> + temp_node1 = xmlNewChild(root, NULL, BAD_CAST "interface", NULL); >> + if (temp_node1 == NULL) { >> + msg = XML_ERROR; >> + goto out; >> + } >> + xmlNewProp(temp_node1, BAD_CAST "name", BAD_CAST piface->name); >> + if (piface->eth_type& ETH_TYPE_ETHER_ANY) { >> + if (piface->eth_type& ETH_TYPE_ETHER_SUB_BRIDGE) { >> + str = "bridge"; >> + } else if (piface->eth_type& ETH_TYPE_ETHER_SUB_VLAN) { >> + str = "vlan"; >> + } else { >> + str = "ethernet"; >> + } >> + xmlNewProp(temp_node1, BAD_CAST "type", BAD_CAST str); >> + } >> + >> + if ((piface->pvlan_prop != NULL)&& >> + (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q)) { >> + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "vlan", NULL); >> + snprintf(buf, sizeof(buf), >> + "%d", piface->pvlan_prop->props.prop_8021q.vlan_id); >> + xmlNewProp(temp_node2, BAD_CAST "tag", BAD_CAST buf); >> + temp_node3 = xmlNewChild(temp_node2, NULL, BAD_CAST "interface", NULL); >> + xmlNewProp(temp_node3, BAD_CAST "name", >> + BAD_CAST piface->pvlan_prop->props.prop_8021q.parent); >> + } >> + >> + /* if it is attached to bridge, only above properties could be set */ >> + if (bridge_port_flag == 1) { >> + goto out; >> + } >> + >> + if (piface->pbr_prop != NULL) { >> + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "bridge", NULL); >> + if (piface->pbr_prop->STP == 1) { >> + snprintf(buf, sizeof(buf), "on"); >> + } else { >> + snprintf(buf, sizeof(buf), "off"); >> + } >> + xmlNewProp(temp_node2, BAD_CAST "stp", BAD_CAST buf); >> + if (piface->pbr_prop->delay>= 0) { >> + snprintf(buf, sizeof(buf), "%d", piface->pbr_prop->delay); >> + xmlNewProp(temp_node2, BAD_CAST "delay", BAD_CAST buf); >> + } >> + if ((piface->pbr_prop->port_names != NULL)&& >> + (piface->pbr_prop->port_num> 0)) { >> + for (i = 0; i< piface->pbr_prop->port_num; i++) { >> + pifaceport = eth_ifaceslist_search(plist, >> + piface->pbr_prop->port_names[i]); >> + if (pifaceport == NULL) { >> + CU_DEBUG("failed to find port %s of bridge %s in list.", >> + piface->pbr_prop->port_names[i], piface->name); >> + } else { >> + gen_eth_xmlnode_iface(temp_node2, pifaceport, plist, 1); >> + } >> + } >> + } >> + } >> + >> + if (piface->run_prop.boot_mode == BOOT_MODE_AUTOSTART) { >> + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "start", NULL); >> + xmlNewProp(temp_node2, BAD_CAST "mode", BAD_CAST "onboot"); >> + } else if (piface->run_prop.boot_mode == BOOT_MODE_NONE) { >> + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "start", NULL); >> + xmlNewProp(temp_node2, BAD_CAST "mode", BAD_CAST "none"); >> + } >> + if (piface->mac != NULL) { >> + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "mac", NULL); >> + xmlNewProp(temp_node2, BAD_CAST "address", BAD_CAST piface->mac); >> + } >> + >> + out: >> + return msg; >> +} >> + >> +static const char *gen_eth_xmlnode(xmlNodePtr root, >> + struct EthIfacesList *plist) >> +{ >> + const char *msg = NULL; >> + int i = 0; >> + struct EthIface *piface = NULL; >> + >> + while (i< plist->count) { >> + piface = plist->pifaces[i]; >> + i++; >> + msg = gen_eth_xmlnode_iface(root, piface, plist, 0); >> + if (msg != NULL) { >> + goto out; >> + } >> + } >> + >> + out: >> + return msg; >> +} >> + >> +const char *EthIfaceListTOXML(char **ppxml, >> + struct EthIfacesList *plist, >> + int dump_all_flag) >> +{ >> + const char *msg = NULL; >> + xmlNodePtr root = NULL; >> + >> + root = xmlNewNode(NULL, BAD_CAST "tmp"); >> + if (root == NULL) { >> + msg = "failed to create root node."; >> + goto out; >> + } >> + msg = gen_eth_xmlnode(root, plist); >> + if (msg == NULL) { >> + if (dump_all_flag == 1) { >> + *ppxml = tree_to_xml(root); >> + } else { >> + *ppxml = tree_to_xml(root->children); >> + } >> + } >> + >> + out: >> + xmlFreeNode(root); >> + return msg; >> +} >> + >> +static int parse_eth_xmlnode(struct EthIfacesList *plist, xmlNode *inode, >> + int status, char *attached) >> +{ >> + struct EthIface *piface = NULL; >> + xmlNode *child1 = NULL, *child2 = NULL; >> + char *temp = NULL, **ppchar; >> + >> + SAFE_MALLOC(piface, sizeof(struct EthIface)); >> + eth_iface_init(piface); >> + >> + piface->name = get_attr_value(inode, "name"); >> + piface->run_prop.status = status; >> + if (attached != NULL) { >> + piface->attach_bridge = strdup(attached); >> + } >> + temp = get_attr_value(inode, "type"); >> + if (temp != NULL) { >> + if (0 == strcmp(temp, "ethernet")) { > By convention, we compare the function result with a value, in that order. > Ex: > > strcmp(temp, "ethernet") == 0 > ok. >> + piface->eth_type = ETH_TYPE_ETHER_ANY; >> + } >> + if (0 == strcmp(temp, "bridge")) { >> + piface->eth_type = ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_BRIDGE; >> + } >> + if (0 == strcmp(temp, "vlan")) { >> + piface->eth_type = ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_VLAN; >> + } >> + SAFE_FREE(temp); >> + } >> + >> + for (child1 = inode->children; child1 != NULL; child1 = child1->next) { >> + if (XSTREQ(child1->name, "start")) { >> + temp = get_attr_value(child1, "mode"); >> + if (0 == strcmp(temp, "onboot")) { >> + piface->run_prop.boot_mode = BOOT_MODE_AUTOSTART; >> + } >> + if (0 == strcmp(temp, "none")) { >> + piface->run_prop.boot_mode = BOOT_MODE_NONE; >> + } >> + SAFE_FREE(temp); >> + } >> + if (XSTREQ(child1->name, "mac")) { >> + piface->mac = get_attr_value(child1, "address"); >> + } >> + if (XSTREQ(child1->name, "bridge")) { >> + eth_iface_add_br_prop(piface); >> + temp = get_attr_value(child1, "stp"); >> + if (0 == strcmp(temp, "on")) { >> + piface->pbr_prop->STP = 1; >> + } >> + if (0 == strcmp(temp, "off")) { >> + piface->pbr_prop->STP = 0; >> + } >> + SAFE_FREE(temp); >> + temp = get_attr_value(child1, "delay"); >> + piface->pbr_prop->delay = strtol(temp, NULL, 10); >> + SAFE_FREE(temp); >> + } >> + if (XSTREQ(child1->name, "bridge")) { >> + eth_iface_add_br_prop(piface); >> + temp = get_attr_value(child1, "stp"); >> + if (0 == strcmp(temp, "on")) { >> + piface->pbr_prop->STP = 1; >> + } >> + if (0 == strcmp(temp, "off")) { >> + piface->pbr_prop->STP = 0; >> + } >> + SAFE_FREE(temp); >> + temp = get_attr_value(child1, "delay"); >> + piface->pbr_prop->delay = strtol(temp, NULL, 10); >> + SAFE_FREE(temp); >> + for (child2 = child1->children; child2 != NULL; >> + child2 = child2->next) { >> + if (XSTREQ(child2->name, "interface")) { >> + if (piface->pbr_prop->port_names == NULL) { >> + SAFE_CALLOC(piface->pbr_prop->port_names, >> + MAX_IFACE_NUM, sizeof(char *)); >> + piface->pbr_prop->port_num = 0; >> + } >> + ppchar = piface->pbr_prop->port_names + >> + (piface->pbr_prop->port_num)++; >> + *ppchar = get_attr_value(child2, "name"); >> + parse_eth_xmlnode(plist, child2, status, piface->name); >> + } >> + } >> + } >> + if (XSTREQ(child1->name, "vlan")) { >> + eth_iface_add_vlan_prop(piface, VLAN_TYPE_802_1_Q); >> + temp = get_attr_value(child1, "tag"); >> + piface->pvlan_prop->props.prop_8021q.vlan_id = >> + strtol(temp, NULL, 10); >> + SAFE_FREE(temp); >> + for (child2 = child1->children; child2 != NULL; >> + child2 = child2->next) { >> + if (XSTREQ(child2->name, "interface")) { >> + piface->pvlan_prop->props.prop_8021q.parent = >> + get_attr_value(child2, "name"); >> + piface->dep_ifname = >> + get_attr_value(child2, "name"); >> + } >> + } >> + } >> + } >> + >> + eth_ifaceslist_add(plist,&piface); >> + return 1; >> +} >> + >> +static const char *XMLToEthIfaceList(struct EthIfacesList *plist, >> + const char *xml, >> + int status) >> +{ >> + xmlDoc *xmldoc; >> + xmlXPathContext *xpathCtx; >> + xmlXPathObject *xpathObj; >> + xmlChar *xpathstr; >> + xmlNode **dev_nodes = NULL; >> + xmlNodeSet *nsv = NULL; >> + int count = 0; >> + int len, devidx; >> + const char *msg = NULL; > init everything possible >> + >> + len = strlen(xml) + 1; >> + xpathstr = (xmlChar *)"/interface"; >> + >> + xmlSetGenericErrorFunc(NULL, swallow_err_msg); >> + if ((xmldoc = xmlParseMemory(xml, len)) == NULL) { >> + msg = "failed to get xmldoc."; >> + goto err1; >> + } >> + >> + if ((xpathCtx = xmlXPathNewContext(xmldoc)) == NULL) { >> + msg = "failed to get pathCtx"; >> + goto err2; >> + } >> + >> + if ((xpathObj = xmlXPathEvalExpression(xpathstr, xpathCtx)) >> + == NULL) { >> + msg = "failed to get xpathObj"; >> + goto err3; >> + } >> + >> + nsv = xpathObj->nodesetval; >> + if (nsv == NULL) { >> + msg = "failed to get nodesetval."; >> + goto out; >> + } >> + >> + dev_nodes = nsv->nodeTab; >> + count = nsv->nodeNr; >> + >> + if (count<= 0) { >> + msg = "nodesetval have less that 1 values."; >> + goto out; >> + } >> + >> + for (devidx = 0; devidx< count; devidx++) { >> + parse_eth_xmlnode(plist, dev_nodes[devidx], status, NULL); >> + } >> + >> + out: >> + xmlSetGenericErrorFunc(NULL, NULL); >> + xmlXPathFreeObject(xpathObj); >> + >> + err3: >> + xmlXPathFreeContext(xpathCtx); >> + err2: >> + xmlFreeDoc(xmldoc); >> + err1: >> + return msg; >> +} >> + >> +CMPIStatus get_host_ifaces(struct EthIfacesList *plist, >> + const CMPIBroker *broker, char *prefix) >> +{ >> + virConnectPtr conn = NULL; >> + virInterfacePtr iface; >> + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; >> + int num, listnum, i; >> + char **names = NULL; >> + char *dump = NULL; >> + int flags = 0; >> + const char *msg; >> + >> + conn = connect_by_classname(broker, prefix,&s); >> + if (conn == NULL) { >> + RECORD_MSG(broker,&s, CMPI_RC_ERR_FAILED, "connect failed."); > I think there is already a macro for this. CMReturn() and CIMReturnWithString(). See cmpimacs.h. the purpose of this macro is to allow broker to be set to NULL which would happen in the test program. If you wish I would remove this macro and write "if (broker != NULL)" directly. >> + goto out; >> + } >> + >> + /* list defined interfaces*/ >> + num = virConnectNumOfDefinedInterfaces(conn); >> + if (num< 0) { >> + RECORD_MSG(broker,&s, CMPI_RC_ERR_FAILED, >> + "failed to find number of defined interfaces."); >> + goto out; >> + } >> + names = malloc(num * sizeof(char *)); >> + listnum = virConnectListDefinedInterfaces(conn, names, num); >> + if (listnum< 0) { >> + RECORD_MSG(broker,&s, CMPI_RC_ERR_FAILED, >> + "failed to list names of defined interfaces."); >> + goto out; >> + } >> + CU_DEBUG("%d defined ifaces found from libvirt API.\n", listnum); >> + >> + flags |= VIR_INTERFACE_XML_INACTIVE; > Good. We should be fetching the stored XML and not just that of the running VM. >> + for (i = 0; i< listnum; i++) { >> + iface = virInterfaceLookupByName(conn, names[i]); >> + if (!iface) { >> + CU_DEBUG("failed to look up %s.\n", names[i]); >> + SAFE_FREE(names[i]); >> + continue; >> + } >> + SAFE_FREE(names[i]); >> + dump = virInterfaceGetXMLDesc(iface, flags); >> + CU_DEBUG("defined interface %d xml:\n%s", i, dump); >> + msg = XMLToEthIfaceList(plist, dump, 0); >> + if (msg != NULL) { >> + CU_DEBUG("failed parsing eth xml, msg is: %s.", msg); >> + } >> + SAFE_FREE(dump); >> + virInterfaceFree(iface); >> + } >> + SAFE_FREE(names); > I recently did some work and avoided using the existing get_devices() internal API to avoid excessive parsing. I'd like to re-factor the existing device parsing APIs to be more re-usable without the overhead. See my second comment in this post . Do you mean that the API should be able to list active or inactive ones according to another parameter? >> + >> + /* list active interfaces*/ >> + num = virConnectNumOfInterfaces(conn); >> + if (num< 0) { >> + RECORD_MSG(broker,&s, CMPI_RC_ERR_FAILED, >> + "failed to find number of active interfaces."); >> + goto out; >> + } >> + names = malloc(num * sizeof(char *)); >> + >> + listnum = virConnectListInterfaces(conn, names, num); >> + if (listnum< 0) { >> + RECORD_MSG(broker,&s, CMPI_RC_ERR_FAILED, >> + "failed to list names of active interfacess."); >> + goto out; >> + } >> + CU_DEBUG("%d active ifaces found from libvirt API.\n", listnum); >> + >> + flags |= VIR_INTERFACE_XML_INACTIVE; >> + for (i = 0; i< listnum; i++) { >> + iface = virInterfaceLookupByName(conn, names[i]); >> + if (!iface) { >> + CU_DEBUG("failed to look up %s.\n", names[i]); >> + SAFE_FREE(names[i]); >> + continue; >> + } >> + SAFE_FREE(names[i]); >> + dump = virInterfaceGetXMLDesc(iface, flags); > Why not rename the dump variable to xml? right. >> + CU_DEBUG("active interface %d xml:\n%s", i, dump); > Nit: In general, we've tried to capitalize the first letter of debug message so they are more like normal sentences. IMO, it makes reading logs a tiny bit easier. >> + msg = XMLToEthIfaceList(plist, dump, 1); >> + if (msg != NULL) { >> + CU_DEBUG("failed parsing eth xml, msg is: %s.", msg); >> + } >> + SAFE_FREE(dump); >> + virInterfaceFree(iface); >> + } >> + s.rc = CMPI_RC_OK; >> + >> + out: >> + virConnectClose(conn); >> + SAFE_FREE(names); >> + return s; >> +} >> +/* >> + * Local Variables: >> + * mode: C >> + * c-set-style: "K&R" >> + * tab-width: 8 >> + * c-basic-offset: 8 >> + * indent-tabs-mode: nil >> + * End: >> + */ >> diff --git a/libxkutil/network_parsing.h b/libxkutil/network_parsing.h >> new file mode 100644 >> index 0000000..bbfe729 >> --- /dev/null >> +++ b/libxkutil/network_parsing.h >> @@ -0,0 +1,160 @@ >> +/* >> + * Copyright IBM Corp. 2012 >> + * >> + * Authors: >> + * Wenchao Xia >> + * >> + * This library is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU Lesser General Public >> + * License as published by the Free Software Foundation; either >> + * version 2.1 of the License, or (at your option) any later version. >> + */ >> + >> +#ifndef NETWORK_PARSING_H >> +#define NETWORK_PARSING_H >> + >> +#include >> +#include >> +#include >> + >> +/* value defines */ >> +#define MAX_IFACE_NUM 4096 >> + >> +#define NUM_NOT_GOT -1 >> + >> +#define ETH_TYPE_BASE_MASK 0xff00 >> +#define ETH_TYPE_SUB_MASK 0x00ff >> + >> +#define CMD_DEBUG_LEVEL 2 >> + >> +/* macro functions */ >> +#define CMD_DEBUG(lvl, fmt, args...) do { \ >> + if (CMD_DEBUG_LEVEL&& (lvl)<= CMD_DEBUG_LEVEL) { \ >> + debug_print(fmt, ##args); \ >> + } \ >> +} while (0) > I assume this exists to reduce noise in the current libvirt-cim log out put (CU_DEBUG), right? Perhaps should simply extend the current impl and add a CU_DEBUG_LEVEL? For now, I'm okay with this as-is. > yes, the macro is made to allow filter out some debug message and more it does not contain a head like "*.c:556 " so some printing could be more formated.I'd like to rename this macro to CU_DEBUG_OPTIONAL. >> + >> +#define SAFE_MALLOC(p, size) \ >> +{ \ >> + (p) = malloc((size)); \ >> + if ((p) == NULL) { \ >> + CU_DEBUG("malloc failed."); \ >> + } \ >> +} >> + >> +#define SAFE_CALLOC(p, nmen, size) \ >> +{ \ >> + (p) = calloc((nmen), (size)); \ >> + if ((p) == NULL) { \ >> + CU_DEBUG("calloc failed."); \ >> + } \ >> +} > These are not really 'safe' since the program will likely crash once p is accessed. Rather, they just hide the return code checking. I know it's a lot of code, but I would prefer we put logic like these where the functions are called. Ideally, we'd all move to this sort of approach and handle any abort gracefully. Until, let's keep things simple (and verbose). The macro did not do as its name. My thought is that if malloc fails, it have a record in debug file, and in future it can acts like a hook, and we can remove the checking of the code in the macro if code seems too much. >> + >> +#define SAFE_FREE(p) {free(p); (p) = NULL; } >> + >> +#define RECORD_MSG(broker, ps, rc, fmt, args...) do { \ >> + CU_DEBUG(fmt, ##args); \ >> + if (broker) { \ >> + cu_statusf((broker), (ps), (rc), fmt, ##args); \ >> + } \ >> +} while (0) > Ah, you're macro takes a variable number of args. See virt_set_status is misc_util.h. virt_set_status is a function, what could I do to the macro according to that? >> + >> +typedef enum { >> + ETH_TYPE_NOT_GOT = 0x0000, > The 'NOT_GOT' is hard to read, IMO. How about just using '_NONE'? OK. >> + ETH_TYPE_ETHER_ANY = 0x0100, >> + ETH_TYPE_ETHER_SUB_PHYSICAL = 0x0001, >> + ETH_TYPE_ETHER_SUB_BRIDGE = 0x0002, >> + ETH_TYPE_ETHER_SUB_VLAN = 0x0004 >> +} EthType; >> + >> +typedef enum { >> + VLAN_TYPE_NOT_GOT = NUM_NOT_GOT, >> + VLAN_TYPE_802_1_Q = 1, >> + VLAN_TYPE_802_1_QBG = 2, >> + VLAN_TYPE_802_1_QBH = 4 >> +} VLANType; >> + >> +typedef enum { >> + BOOT_MODE_NOT_GOT = NUM_NOT_GOT, >> + BOOT_MODE_AUTOSTART = 1, >> + BOOT_MODE_NONE = 2 >> +} BootMode; >> + >> +struct BR_Prop { >> + int STP; >> + int delay; >> + char **port_names; >> + int port_num; >> +} ; >> + >> +struct Run_Prop { >> + int status; >> + BootMode boot_mode; >> +} ; >> + >> +struct VLAN_Prop_8021q { >> + int vlan_id; >> + char *parent; >> +} ; >> + >> +/* HP vlan standard, TBD */ >> +struct VLAN_Prop_8021qbg { >> + int invalid; >> +} ; >> + >> +/* Cisco and VMware vlan standard, TBD */ >> +struct VLAN_Prop_8021qbh { >> + int invalid; >> +} ; >> + >> +struct VLAN_Prop { >> + int vlan_type; >> + union { >> + struct VLAN_Prop_8021q prop_8021q; >> + struct VLAN_Prop_8021qbg prop_8021qbg; >> + struct VLAN_Prop_8021qbh prop_8021qbh; >> + } props; >> +} ; >> + >> +/* EthIface is logical devices include eth ports and bridges */ >> +struct EthIface { >> + char *name; >> + char *dep_ifname; /* parent dev name */ >> + char *attach_bridge; /* bridge the iface is attached to */ >> + char *mac; >> + EthType eth_type; >> + struct Run_Prop run_prop; >> + /* optional properties */ >> + struct BR_Prop *pbr_prop; >> + struct VLAN_Prop *pvlan_prop; >> +} ; >> + >> +struct EthIfacesList { >> + struct EthIface *pifaces[MAX_IFACE_NUM]; >> + int count; >> +} ; >> + >> +void eth_iface_init(struct EthIface *piface); >> +void eth_iface_add_br_prop(struct EthIface *piface); >> +void eth_iface_add_vlan_prop(struct EthIface *piface, int vlan_type); >> +void eth_iface_uninit(struct EthIface *piface); >> + >> +void eth_ifaceslist_init(struct EthIfacesList *plist); >> +void eth_ifaceslist_uninit(struct EthIfacesList *plist); >> +/* ppiface must be allocated from heap, to save code of struct duplication */ >> +int eth_ifaceslist_add(struct EthIfacesList *plist, struct EthIface **ppiface); >> +/* returned pointer is direct reference to a member in plist */ >> +struct EthIface *eth_ifaceslist_search(struct EthIfacesList *plist, >> + char *name); >> + >> +void eth_iface_print(struct EthIface *piface); >> +void eth_ifaceslist_print(struct EthIfacesList *plist); >> + >> +CMPIStatus get_host_ifaces(struct EthIfacesList *plist, >> + const CMPIBroker *broker, char *prefix); >> + >> +const char *EthIfaceListTOXML(char **ppxml, >> + struct EthIfacesList *plist, >> + int dump_all_flag); >> + >> +#endif >> diff --git a/libxkutil/network_parsing_test.c b/libxkutil/network_parsing_test.c >> new file mode 100644 >> index 0000000..593bfd0 >> --- /dev/null >> +++ b/libxkutil/network_parsing_test.c > Copyright? sorry, forgot that. >> @@ -0,0 +1,61 @@ >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include >> +#include >> +#include >> + >> +#include "misc_util.h" >> +#include "device_parsing.h" >> +#include "network_parsing.h" >> + >> +static const CMPIBroker *broker; >> + >> +static long print_and_ret_time_stamp(void) >> +{ >> + struct timeval tv; >> + long ret; >> + gettimeofday(&tv, NULL); >> + ret = tv.tv_sec*1000 + tv.tv_usec/1000; >> + CU_DEBUG("time is [%ld] ms.", ret); >> + return ret; >> +} >> + >> +/* try retrieve all information, and then map them back to xml. */ >> +int main(int argc, char **argv) >> +{ >> + libvirt_cim_init(); >> + struct EthIfacesList *plist = NULL; >> + const char *msg = NULL; >> + char *genxml = NULL; >> + CMPIStatus s; >> + long start_time, end_time; >> + >> + SAFE_MALLOC(plist, sizeof(struct EthIfacesList)); >> + eth_ifaceslist_init(plist); >> + >> + start_time = print_and_ret_time_stamp(); >> + s = get_host_ifaces(plist, broker, "kvm"); >> + end_time = print_and_ret_time_stamp(); >> + CU_DEBUG("cost [%d]ms in discovering host network. Result:", >> + end_time - start_time); >> + eth_ifaceslist_print(plist); >> + >> + msg = EthIfaceListTOXML(&genxml, plist, 1); >> + CU_DEBUG("xml gen msg is %s. xml is:\n%s", msg, genxml); >> + SAFE_FREE(genxml); >> + >> + eth_ifaceslist_uninit(plist); >> + SAFE_FREE(plist); >> + return 0; >> +} >> diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c >> index 9a2ada9..001246a 100644 >> --- a/libxkutil/xmlgen.c >> +++ b/libxkutil/xmlgen.c >> @@ -830,7 +830,7 @@ static char *features_xml(xmlNodePtr root, struct domain *domain) >> return NULL; >> } >> >> -static char *tree_to_xml(xmlNodePtr root) >> +char *tree_to_xml(xmlNodePtr root) >> { >> xmlBufferPtr buffer = NULL; >> xmlSaveCtxtPtr savectx = NULL; >> diff --git a/libxkutil/xmlgen.h b/libxkutil/xmlgen.h >> index 743fc82..5d21a94 100644 >> --- a/libxkutil/xmlgen.h >> +++ b/libxkutil/xmlgen.h >> @@ -32,6 +32,8 @@ struct kv { >> const char *val; >> }; >> >> +char *tree_to_xml(xmlNodePtr root); >> + > Good re-use! >> char *system_to_xml(struct domain *dominfo); >> char *device_to_xml(struct virt_device *dev); >> > > From xiaxia347work at 163.com Fri Jan 27 14:05:28 2012 From: xiaxia347work at 163.com (xiaxia347work) Date: Fri, 27 Jan 2012 22:05:28 +0800 Subject: [Libvirt-cim] [PATCH v5] vlan extention - add function library for readonly usage In-Reply-To: <1327602968.4193.1265.camel@snmishra-desktop.beaverton.ibm.com> References: <1327521897-17291-1-git-send-email-xiaxia347work@163.com><1327602968.4193.1265.camel@snmishra-desktop.beaverton.ibm.com> Message-ID: <66b57fe6.7f8f.1351f7c501f.Coremail.xiaxia347work@163.com> > Code looks good. I have marked some nits. Take a look. > I have not yet applied the patch or done any testing. > > When do we see the actual provider? This patch is more of a > backend/infrastructure. We will also need a CIM layer. > > -Sharad Mishra > OK, Soon I will send the provider with improved library code. > On Thu, 2012-01-26 at 04:04 +0800, xiaxia347work at 163.com wrote: >> From: Wenchao Xia >> >> This patch contain 1 test program and 1 c file doing xml and structure >> mapping. It expose some API to translate xml to device structure, in a similar >> way to code in device_parsing.c. Also some other files are changed to let new >> code use their internal functions. Type following Command in libxkutil >> directory: >> sudo CU_DEBUG=stdout .libs/network_parsing_test >> could see what it have done. >> >> v5: calling libvirt API which employ netcf instead of using libnl. From git log >> these API are available since 0.9.2, and this patch is tested with libvirt >> 0.9.4. >> >> Signed-off-by: Wenchao Xia >> --- >> libxkutil/Makefile.am | 12 +- >> libxkutil/misc_util.c | 10 +- >> libxkutil/network_parsing.c | 665 ++++++++++++++++++++++++++++++++++++++ >> libxkutil/network_parsing.h | 160 +++++++++ >> libxkutil/network_parsing_test.c | 61 ++++ >> libxkutil/xmlgen.c | 2 +- >> libxkutil/xmlgen.h | 2 + >> 7 files changed, 906 insertions(+), 6 deletions(-) >> create mode 100644 libxkutil/network_parsing.c >> create mode 100644 libxkutil/network_parsing.h >> create mode 100644 libxkutil/network_parsing_test.c >> >> diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am >> index f1adc03..c0e62eb 100644 >> --- a/libxkutil/Makefile.am >> +++ b/libxkutil/Makefile.am >> @@ -4,12 +4,14 @@ AM_CFLAGS = $(CFLAGS_STRICT) \ >> -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" >> >> noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ >> - pool_parsing.h acl_parsing.h >> + pool_parsing.h acl_parsing.h \ >> + network_parsing.h >> >> lib_LTLIBRARIES = libxkutil.la >> >> libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ >> - xmlgen.c infostore.c pool_parsing.c acl_parsing.c >> + xmlgen.c infostore.c pool_parsing.c acl_parsing.c \ >> + network_parsing.c >> libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ >> libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ >> @LIBUUID_LIBS@ >> @@ -19,3 +21,9 @@ noinst_PROGRAMS = xml_parse_test >> xml_parse_test_SOURCES = xml_parse_test.c >> xml_parse_test_LDADD = libxkutil.la \ >> @LIBVIRT_LIBS@ >> + >> +noinst_PROGRAMS += network_parsing_test >> + >> +network_parsing_test_SOURCES = network_parsing_test.c >> +network_parsing_test_LDADD = libxkutil.la \ >> + @LIBVIRT_LIBS@ >> diff --git a/libxkutil/misc_util.c b/libxkutil/misc_util.c >> index 61893c3..1c18c33 100644 >> --- a/libxkutil/misc_util.c >> +++ b/libxkutil/misc_util.c >> @@ -152,9 +152,13 @@ virConnectPtr connect_by_classname(const CMPIBroker *broker, >> >> uri = cn_to_uri(classname); >> if (!uri) { >> - cu_statusf(broker, s, >> - CMPI_RC_ERR_FAILED, >> - "Unable to generate URI from classname"); >> + if (broker) { >> + cu_statusf(broker, s, >> + CMPI_RC_ERR_FAILED, >> + "Unable to generate URI from classname"); >> + } >> + CU_DEBUG("Unable to generate URI from classname," >> + " uri is %s.", uri); >> return NULL; >> } >> >> diff --git a/libxkutil/network_parsing.c b/libxkutil/network_parsing.c >> new file mode 100644 >> index 0000000..932000c >> --- /dev/null >> +++ b/libxkutil/network_parsing.c >> @@ -0,0 +1,665 @@ >> +/* >> + * Copyright IBM Corp. 2012 >> + * >> + * Authors: >> + * Wenchao Xia >> + * >> + * This library is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU Lesser General Public >> + * License as published by the Free Software Foundation; either >> + * version 2.1 of the License, or (at your option) any later version. >> + * >> + * This library is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >> + * Lesser General Public License for more details. >> + * >> + * You should have received a copy of the GNU Lesser General Public >> + * License along with this library; if not, write to the Free Software >> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA >> + */ >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include "misc_util.h" >> +#include "xmlgen.h" >> +#include "device_parsing.h" >> +#include "network_parsing.h" >> + >> +#define XML_ERROR "Failed to allocate XML memory" >> + >> +static void vlan_prop_print(struct VLAN_Prop *pvlan_prop) >> +{ >> + struct VLAN_Prop_8021q *p_8021q; >> + CMD_DEBUG(1, "--VLAN props: type %d.\n", >> + pvlan_prop->vlan_type); >> + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { >> + p_8021q = &(pvlan_prop->props.prop_8021q); >> + CMD_DEBUG(1, "----IEEE802.1.Q: id %d, parent %s.\n", >> + p_8021q->vlan_id, p_8021q->parent); >> + } >> +} >> + >> +static void br_prop_print(struct BR_Prop *pbr_prop) >> +{ >> + int i = 0; >> + CMD_DEBUG(1, "--Bridge props: stp %d, delay %d, port_num %d.\n", >> + pbr_prop->STP, pbr_prop->delay, pbr_prop->port_num); >> + if (pbr_prop->port_names != NULL) { >> + CMD_DEBUG(1, "----Ports attached: "); >> + while (i < pbr_prop->port_num) { >> + CMD_DEBUG(1, " %s,", *(pbr_prop->port_names+i)); >> + i++; >> + } >> + CMD_DEBUG(1, "\n"); >> + } >> +} >> + >> +void eth_iface_print(struct EthIface *piface) >> +{ >> + CMD_DEBUG(1, "Iface device: name %s.\n" >> + "--Main Props: parent %s, attach to %s, mac %s," >> + " status %d, boot_mode %d, iface type 0x%x.\n", >> + piface->name, piface->dep_ifname, piface->attach_bridge, >> + piface->mac, >> + piface->run_prop.status, piface->run_prop.boot_mode, piface->eth_type); >> + if (piface->pbr_prop != NULL) { >> + br_prop_print(piface->pbr_prop); >> + } >> + if (piface->pvlan_prop != NULL) { >> + vlan_prop_print(piface->pvlan_prop); >> + } >> + return; >> +} >> + >> +void eth_ifaceslist_print(struct EthIfacesList *plist) >> +{ >> + int i = 0; >> + CMD_DEBUG(1, "Have %d ifaces in the list:\n", plist->count); >> + while (i < plist->count) { >> + CMD_DEBUG(1, "%04d ", i); >> + eth_iface_print(plist->pifaces[i]); >> + i++; >> + } >> +} >> + >> +static void vlan_prop_init(struct VLAN_Prop *pvlan_prop, int vlan_type) >> +{ >> + struct VLAN_Prop_8021q *p_8021q; >> + memset(pvlan_prop, 0, sizeof(struct VLAN_Prop)); >> + pvlan_prop->vlan_type = vlan_type; >> + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { >> + p_8021q = &(pvlan_prop->props.prop_8021q); >> + p_8021q->vlan_id = NUM_NOT_GOT; >> + } >> +} >> + >> +static void br_prop_init(struct BR_Prop *pbr_prop) >> +{ >> + memset(pbr_prop, 0, sizeof(struct BR_Prop)); >> + pbr_prop->STP = NUM_NOT_GOT; >> + pbr_prop->delay = NUM_NOT_GOT; >> + pbr_prop->port_num = NUM_NOT_GOT; >> +} >> + >> +void eth_iface_init(struct EthIface *piface) >> +{ >> + memset(piface, 0, sizeof(struct EthIface)); >> + piface->eth_type = ETH_TYPE_NOT_GOT; >> + piface->run_prop.status = NUM_NOT_GOT; >> + piface->run_prop.boot_mode = BOOT_MODE_NOT_GOT; >> + return; >> +} >> + >> +void eth_iface_add_br_prop(struct EthIface *piface) >> +{ >> + if (piface->pbr_prop != NULL) { >> + return; >> + } >> + SAFE_MALLOC(piface->pbr_prop, sizeof(struct BR_Prop)); >> + br_prop_init(piface->pbr_prop); >> +} >> + >> +void eth_iface_add_vlan_prop(struct EthIface *piface, int vlan_type) >> +{ >> + if (piface->pvlan_prop != NULL) { >> + return; >> + } >> + SAFE_MALLOC(piface->pvlan_prop, sizeof(struct VLAN_Prop)); >> + vlan_prop_init(piface->pvlan_prop, vlan_type); >> +} >> + >> +static void vlan_prop_uninit(struct VLAN_Prop *pvlan_prop) >> +{ >> + struct VLAN_Prop_8021q *p_8021q; >> + if (pvlan_prop == NULL) { >> + return; >> + } >> + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { >> + p_8021q = &(pvlan_prop->props.prop_8021q); >> + SAFE_FREE(p_8021q->parent); >> + } >> +} >> + >> +static void br_prop_uninit(struct BR_Prop *pbr_prop) >> +{ >> + int i; >> + if (pbr_prop == NULL) { >> + return; >> + } >> + i = 0; >> + if (pbr_prop->port_names != NULL) { >> + while (i < pbr_prop->port_num) { >> + SAFE_FREE(pbr_prop->port_names[i]); >> + i++; >> + } >> + SAFE_FREE(pbr_prop->port_names); >> + } >> +} >> + >> +void eth_iface_uninit(struct EthIface *piface) >> +{ >> + if (piface == NULL) { >> + return; >> + } >> + SAFE_FREE(piface->name); >> + SAFE_FREE(piface->dep_ifname); >> + SAFE_FREE(piface->attach_bridge); >> + SAFE_FREE(piface->mac); >> + br_prop_uninit(piface->pbr_prop); >> + SAFE_FREE(piface->pbr_prop); >> + vlan_prop_uninit(piface->pvlan_prop); >> + SAFE_FREE(piface->pvlan_prop); >> + return; >> +} >> + >> +void eth_ifaceslist_init(struct EthIfacesList *plist) >> +{ >> + plist->count = 0; >> +} >> + >> +void eth_ifaceslist_uninit(struct EthIfacesList *plist) >> +{ >> + struct EthIface **t; >> + int i; >> + if (plist->count <= 0) { >> + return; >> + } >> + t = plist->pifaces; >> + i = 0; >> + while (i < plist->count) { >> + if (*t != NULL) { >> + eth_iface_uninit(*t); >> + SAFE_FREE(*t); >> + } >> + t++; >> + i++; >> + } >> + return; >> +} >> + >> +int eth_ifaceslist_add(struct EthIfacesList *plist, struct EthIface **ppiface) >> +{ >> + if (plist->count >= MAX_IFACE_NUM) { >> + CU_DEBUG("too much device found."); >> + return 0; >> + } >> + plist->pifaces[plist->count] = *ppiface; >> + *ppiface = NULL; >> + plist->count++; >> + return 1; >> +} >> + >> +struct EthIface *eth_ifaceslist_search(struct EthIfacesList *plist, >> + char *name) >> +{ >> + int i = 0; >> + struct EthIface *piface = NULL; >> + >> + while (i < plist->count) { >> + piface = plist->pifaces[i]; >> + i++; >> + if (piface != NULL) { >> + if (0 == strcmp(piface->name, name)) { > > can we do "if (strcmp(piface->name, name) == 0) { " ? OK, just my custom. >> + return piface; >> + } >> + } >> + } >> + return NULL; >> +} >> + >> +/* Dummy function to suppress error message from libxml2 */ >> +static void swallow_err_msg(void *ctx, const char *msg, ...) >> +{ >> + /* do nothing, just swallow the message. */ >> +} >> + >> + >> +static const char *gen_eth_xmlnode_iface(xmlNodePtr root, >> + struct EthIface *piface, >> + struct EthIfacesList *plist, >> + int bridge_port_flag) >> +{ >> + const char *msg = NULL; >> + xmlNodePtr temp_node1 = NULL, temp_node2 = NULL, temp_node3 = NULL; >> + char *str, buf[16]; >> + int i; >> + struct EthIface *pifaceport; >> + >> + if (piface->name == NULL) { >> + msg = "iface have no name.\n"; >> + goto out; >> + } >> + /* netcfg have no xml for iface attatched to bridge */ >> + if ((piface->attach_bridge != NULL) && (bridge_port_flag != 1)) { > > What are you trying to eliminate here? > what I observed is that in netcf, if one eth is attached to a bridge, it have no a "stand along" xml for it, so jump out. and if bride_port_flag == 1, it means try to generate a embbed xml node with limited property, do not jump out. the function is re-entered later so need this flag making difference. >> + goto out; >> + } >> + >> + temp_node1 = xmlNewChild(root, NULL, BAD_CAST "interface", NULL); >> + if (temp_node1 == NULL) { >> + msg = XML_ERROR; >> + goto out; >> + } >> + xmlNewProp(temp_node1, BAD_CAST "name", BAD_CAST piface->name); >> + if (piface->eth_type & ETH_TYPE_ETHER_ANY) { > > why do we require the above check? Can it be eliminated and just use the > checks below? > right. >> + if (piface->eth_type & ETH_TYPE_ETHER_SUB_BRIDGE) { >> + str = "bridge"; >> + } else if (piface->eth_type & ETH_TYPE_ETHER_SUB_VLAN) { >> + str = "vlan"; >> + } else { >> + str = "ethernet"; >> + } >> + xmlNewProp(temp_node1, BAD_CAST "type", BAD_CAST str); >> + } >> + >> + if ((piface->pvlan_prop != NULL) && >> + (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q)) { >> + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "vlan", NULL); >> + snprintf(buf, sizeof(buf), >> + "%d", piface->pvlan_prop->props.prop_8021q.vlan_id); >> + xmlNewProp(temp_node2, BAD_CAST "tag", BAD_CAST buf); >> + temp_node3 = xmlNewChild(temp_node2, NULL, BAD_CAST "interface", NULL); >> + xmlNewProp(temp_node3, BAD_CAST "name", >> + BAD_CAST piface->pvlan_prop->props.prop_8021q.parent); >> + } >> + >> + /* if it is attached to bridge, only above properties could be set */ >> + if (bridge_port_flag == 1) { >> + goto out; >> + } >> + >> + if (piface->pbr_prop != NULL) { >> + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "bridge", NULL); >> + if (piface->pbr_prop->STP == 1) { >> + snprintf(buf, sizeof(buf), "on"); >> + } else { >> + snprintf(buf, sizeof(buf), "off"); >> + } >> + xmlNewProp(temp_node2, BAD_CAST "stp", BAD_CAST buf); >> + if (piface->pbr_prop->delay >= 0) { >> + snprintf(buf, sizeof(buf), "%d", piface->pbr_prop->delay); >> + xmlNewProp(temp_node2, BAD_CAST "delay", BAD_CAST buf); >> + } >> + if ((piface->pbr_prop->port_names != NULL) && >> + (piface->pbr_prop->port_num > 0)) { >> + for (i = 0; i < piface->pbr_prop->port_num; i++) { >> + pifaceport = eth_ifaceslist_search(plist, >> + piface->pbr_prop->port_names[i]); >> + if (pifaceport == NULL) { >> + CU_DEBUG("failed to find port %s of bridge %s in list.", >> + piface->pbr_prop->port_names[i], piface->name); >> + } else { >> + gen_eth_xmlnode_iface(temp_node2, pifaceport, plist, 1); >> + } >> + } >> + } >> + } >> + >> + if (piface->run_prop.boot_mode == BOOT_MODE_AUTOSTART) { >> + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "start", NULL); >> + xmlNewProp(temp_node2, BAD_CAST "mode", BAD_CAST "onboot"); >> + } else if (piface->run_prop.boot_mode == BOOT_MODE_NONE) { >> + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "start", NULL); >> + xmlNewProp(temp_node2, BAD_CAST "mode", BAD_CAST "none"); >> + } >> + if (piface->mac != NULL) { >> + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "mac", NULL); >> + xmlNewProp(temp_node2, BAD_CAST "address", BAD_CAST piface->mac); >> + } >> + >> + out: >> + return msg; >> +} >> + >> +static const char *gen_eth_xmlnode(xmlNodePtr root, >> + struct EthIfacesList *plist) >> +{ >> + const char *msg = NULL; >> + int i = 0; >> + struct EthIface *piface = NULL; >> + >> + while (i < plist->count) { >> + piface = plist->pifaces[i]; >> + i++; >> + msg = gen_eth_xmlnode_iface(root, piface, plist, 0); >> + if (msg != NULL) { >> + goto out; >> + } >> + } >> + >> + out: >> + return msg; >> +} >> + >> +const char *EthIfaceListTOXML(char **ppxml, >> + struct EthIfacesList *plist, >> + int dump_all_flag) >> +{ >> + const char *msg = NULL; >> + xmlNodePtr root = NULL; >> + >> + root = xmlNewNode(NULL, BAD_CAST "tmp"); >> + if (root == NULL) { >> + msg = "failed to create root node."; >> + goto out; >> + } >> + msg = gen_eth_xmlnode(root, plist); >> + if (msg == NULL) { >> + if (dump_all_flag == 1) { >> + *ppxml = tree_to_xml(root); >> + } else { >> + *ppxml = tree_to_xml(root->children); >> + } >> + } >> + >> + out: >> + xmlFreeNode(root); >> + return msg; >> +} >> + >> +static int parse_eth_xmlnode(struct EthIfacesList *plist, xmlNode *inode, >> + int status, char *attached) >> +{ >> + struct EthIface *piface = NULL; >> + xmlNode *child1 = NULL, *child2 = NULL; >> + char *temp = NULL, **ppchar; >> + >> + SAFE_MALLOC(piface, sizeof(struct EthIface)); >> + eth_iface_init(piface); >> + >> + piface->name = get_attr_value(inode, "name"); >> + piface->run_prop.status = status; >> + if (attached != NULL) { >> + piface->attach_bridge = strdup(attached); >> + } >> + temp = get_attr_value(inode, "type"); >> + if (temp != NULL) { >> + if (0 == strcmp(temp, "ethernet")) { > > can you change to if(strcmp() == 0) > OK. >> + piface->eth_type = ETH_TYPE_ETHER_ANY; >> + } >> + if (0 == strcmp(temp, "bridge")) { >> + piface->eth_type = ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_BRIDGE; >> + } >> + if (0 == strcmp(temp, "vlan")) { >> + piface->eth_type = ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_VLAN; >> + } >> + SAFE_FREE(temp); >> + } >> + >> + for (child1 = inode->children; child1 != NULL; child1 = child1->next) { >> + if (XSTREQ(child1->name, "start")) { >> + temp = get_attr_value(child1, "mode"); >> + if (0 == strcmp(temp, "onboot")) { > > change as above > >> + piface->run_prop.boot_mode = BOOT_MODE_AUTOSTART; >> + } >> + if (0 == strcmp(temp, "none")) { >> + piface->run_prop.boot_mode = BOOT_MODE_NONE; >> + } >> + SAFE_FREE(temp); >> + } >> + if (XSTREQ(child1->name, "mac")) { >> + piface->mac = get_attr_value(child1, "address"); >> + } >> + if (XSTREQ(child1->name, "bridge")) { >> + eth_iface_add_br_prop(piface); >> + temp = get_attr_value(child1, "stp"); >> + if (0 == strcmp(temp, "on")) { >> + piface->pbr_prop->STP = 1; >> + } >> + if (0 == strcmp(temp, "off")) { >> + piface->pbr_prop->STP = 0; >> + } >> + SAFE_FREE(temp); >> + temp = get_attr_value(child1, "delay"); >> + piface->pbr_prop->delay = strtol(temp, NULL, 10); >> + SAFE_FREE(temp); >> + } >> + if (XSTREQ(child1->name, "bridge")) { >> + eth_iface_add_br_prop(piface); >> + temp = get_attr_value(child1, "stp"); >> + if (0 == strcmp(temp, "on")) { >> + piface->pbr_prop->STP = 1; >> + } >> + if (0 == strcmp(temp, "off")) { >> + piface->pbr_prop->STP = 0; >> + } >> + SAFE_FREE(temp); >> + temp = get_attr_value(child1, "delay"); >> + piface->pbr_prop->delay = strtol(temp, NULL, 10); >> + SAFE_FREE(temp); >> + for (child2 = child1->children; child2 != NULL; >> + child2 = child2->next) { >> + if (XSTREQ(child2->name, "interface")) { >> + if (piface->pbr_prop->port_names == NULL) { >> + SAFE_CALLOC(piface->pbr_prop->port_names, >> + MAX_IFACE_NUM, sizeof(char *)); >> + piface->pbr_prop->port_num = 0; >> + } >> + ppchar = piface->pbr_prop->port_names + >> + (piface->pbr_prop->port_num)++; >> + *ppchar = get_attr_value(child2, "name"); >> + parse_eth_xmlnode(plist, child2, status, piface->name); >> + } >> + } >> + } >> + if (XSTREQ(child1->name, "vlan")) { >> + eth_iface_add_vlan_prop(piface, VLAN_TYPE_802_1_Q); >> + temp = get_attr_value(child1, "tag"); >> + piface->pvlan_prop->props.prop_8021q.vlan_id = >> + strtol(temp, NULL, 10); >> + SAFE_FREE(temp); >> + for (child2 = child1->children; child2 != NULL; >> + child2 = child2->next) { >> + if (XSTREQ(child2->name, "interface")) { >> + piface->pvlan_prop->props.prop_8021q.parent = >> + get_attr_value(child2, "name"); >> + piface->dep_ifname = >> + get_attr_value(child2, "name"); >> + } >> + } >> + } >> + } >> + >> + eth_ifaceslist_add(plist, &piface); >> + return 1; >> +} >> + >> +static const char *XMLToEthIfaceList(struct EthIfacesList *plist, >> + const char *xml, >> + int status) >> +{ >> + xmlDoc *xmldoc; >> + xmlXPathContext *xpathCtx; >> + xmlXPathObject *xpathObj; >> + xmlChar *xpathstr; >> + xmlNode **dev_nodes = NULL; >> + xmlNodeSet *nsv = NULL; >> + int count = 0; >> + int len, devidx; >> + const char *msg = NULL; >> + >> + len = strlen(xml) + 1; >> + xpathstr = (xmlChar *)"/interface"; >> + >> + xmlSetGenericErrorFunc(NULL, swallow_err_msg); >> + if ((xmldoc = xmlParseMemory(xml, len)) == NULL) { >> + msg = "failed to get xmldoc."; >> + goto err1; >> + } >> + >> + if ((xpathCtx = xmlXPathNewContext(xmldoc)) == NULL) { >> + msg = "failed to get pathCtx"; >> + goto err2; >> + } >> + >> + if ((xpathObj = xmlXPathEvalExpression(xpathstr, xpathCtx)) >> + == NULL) { >> + msg = "failed to get xpathObj"; >> + goto err3; >> + } >> + >> + nsv = xpathObj->nodesetval; >> + if (nsv == NULL) { >> + msg = "failed to get nodesetval."; >> + goto out; >> + } >> + >> + dev_nodes = nsv->nodeTab; >> + count = nsv->nodeNr; >> + >> + if (count <= 0) { >> + msg = "nodesetval have less that 1 values."; >> + goto out; >> + } >> + >> + for (devidx = 0; devidx < count; devidx++) { >> + parse_eth_xmlnode(plist, dev_nodes[devidx], status, NULL); >> + } >> + >> + out: >> + xmlSetGenericErrorFunc(NULL, NULL); >> + xmlXPathFreeObject(xpathObj); >> + >> + err3: >> + xmlXPathFreeContext(xpathCtx); >> + err2: >> + xmlFreeDoc(xmldoc); >> + err1: >> + return msg; >> +} >> + >> +CMPIStatus get_host_ifaces(struct EthIfacesList *plist, >> + const CMPIBroker *broker, char *prefix) >> +{ >> + virConnectPtr conn = NULL; >> + virInterfacePtr iface; >> + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; >> + int num, listnum, i; >> + char **names = NULL; >> + char *dump = NULL; >> + int flags = 0; >> + const char *msg; >> + >> + conn = connect_by_classname(broker, prefix, &s); >> + if (conn == NULL) { >> + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, "connect failed."); >> + goto out; >> + } >> + >> + /* list defined interfaces*/ >> + num = virConnectNumOfDefinedInterfaces(conn); >> + if (num < 0) { >> + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, >> + "failed to find number of defined interfaces."); >> + goto out; >> + } >> + names = malloc(num * sizeof(char *)); >> + listnum = virConnectListDefinedInterfaces(conn, names, num); >> + if (listnum < 0) { >> + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, >> + "failed to list names of defined interfaces."); >> + goto out; >> + } >> + CU_DEBUG("%d defined ifaces found from libvirt API.\n", listnum); >> + >> + flags |= VIR_INTERFACE_XML_INACTIVE; >> + for (i = 0; i < listnum; i++) { >> + iface = virInterfaceLookupByName(conn, names[i]); >> + if (!iface) { >> + CU_DEBUG("failed to look up %s.\n", names[i]); >> + SAFE_FREE(names[i]); >> + continue; >> + } >> + SAFE_FREE(names[i]); >> + dump = virInterfaceGetXMLDesc(iface, flags); >> + CU_DEBUG("defined interface %d xml:\n%s", i, dump); >> + msg = XMLToEthIfaceList(plist, dump, 0); >> + if (msg != NULL) { >> + CU_DEBUG("failed parsing eth xml, msg is: %s.", msg); >> + } >> + SAFE_FREE(dump); >> + virInterfaceFree(iface); >> + } >> + SAFE_FREE(names); >> + >> + /* list active interfaces*/ >> + num = virConnectNumOfInterfaces(conn); >> + if (num < 0) { >> + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, >> + "failed to find number of active interfaces."); >> + goto out; >> + } >> + names = malloc(num * sizeof(char *)); >> + >> + listnum = virConnectListInterfaces(conn, names, num); >> + if (listnum < 0) { >> + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, >> + "failed to list names of active interfacess."); >> + goto out; >> + } >> + CU_DEBUG("%d active ifaces found from libvirt API.\n", listnum); >> + >> + flags |= VIR_INTERFACE_XML_INACTIVE; >> + for (i = 0; i < listnum; i++) { >> + iface = virInterfaceLookupByName(conn, names[i]); >> + if (!iface) { >> + CU_DEBUG("failed to look up %s.\n", names[i]); >> + SAFE_FREE(names[i]); >> + continue; >> + } >> + SAFE_FREE(names[i]); >> + dump = virInterfaceGetXMLDesc(iface, flags); >> + CU_DEBUG("active interface %d xml:\n%s", i, dump); >> + msg = XMLToEthIfaceList(plist, dump, 1); >> + if (msg != NULL) { >> + CU_DEBUG("failed parsing eth xml, msg is: %s.", msg); >> + } >> + SAFE_FREE(dump); >> + virInterfaceFree(iface); >> + } >> + s.rc = CMPI_RC_OK; >> + >> + out: >> + virConnectClose(conn); >> + SAFE_FREE(names); >> + return s; >> +} >> +/* >> + * Local Variables: >> + * mode: C >> + * c-set-style: "K&R" >> + * tab-width: 8 >> + * c-basic-offset: 8 >> + * indent-tabs-mode: nil >> + * End: >> + */ >> diff --git a/libxkutil/network_parsing.h b/libxkutil/network_parsing.h >> new file mode 100644 >> index 0000000..bbfe729 >> --- /dev/null >> +++ b/libxkutil/network_parsing.h >> @@ -0,0 +1,160 @@ >> +/* >> + * Copyright IBM Corp. 2012 >> + * >> + * Authors: >> + * Wenchao Xia >> + * >> + * This library is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU Lesser General Public >> + * License as published by the Free Software Foundation; either >> + * version 2.1 of the License, or (at your option) any later version. >> + */ >> + >> +#ifndef NETWORK_PARSING_H >> +#define NETWORK_PARSING_H >> + >> +#include >> +#include >> +#include >> + >> +/* value defines */ >> +#define MAX_IFACE_NUM 4096 >> + >> +#define NUM_NOT_GOT -1 >> + >> +#define ETH_TYPE_BASE_MASK 0xff00 >> +#define ETH_TYPE_SUB_MASK 0x00ff >> + >> +#define CMD_DEBUG_LEVEL 2 >> + >> +/* macro functions */ >> +#define CMD_DEBUG(lvl, fmt, args...) do { \ >> + if (CMD_DEBUG_LEVEL && (lvl) <= CMD_DEBUG_LEVEL) { \ >> + debug_print(fmt, ##args); \ >> + } \ >> +} while (0) >> + >> +#define SAFE_MALLOC(p, size) \ >> +{ \ >> + (p) = malloc((size)); \ >> + if ((p) == NULL) { \ >> + CU_DEBUG("malloc failed."); \ >> + } \ >> +} >> + >> +#define SAFE_CALLOC(p, nmen, size) \ >> +{ \ >> + (p) = calloc((nmen), (size)); \ >> + if ((p) == NULL) { \ >> + CU_DEBUG("calloc failed."); \ >> + } \ >> +} >> + >> +#define SAFE_FREE(p) {free(p); (p) = NULL; } >> + >> +#define RECORD_MSG(broker, ps, rc, fmt, args...) do { \ >> + CU_DEBUG(fmt, ##args); \ >> + if (broker) { \ >> + cu_statusf((broker), (ps), (rc), fmt, ##args); \ >> + } \ >> +} while (0) >> + >> +typedef enum { >> + ETH_TYPE_NOT_GOT = 0x0000, >> + ETH_TYPE_ETHER_ANY = 0x0100, >> + ETH_TYPE_ETHER_SUB_PHYSICAL = 0x0001, >> + ETH_TYPE_ETHER_SUB_BRIDGE = 0x0002, >> + ETH_TYPE_ETHER_SUB_VLAN = 0x0004 >> +} EthType; >> + >> +typedef enum { >> + VLAN_TYPE_NOT_GOT = NUM_NOT_GOT, >> + VLAN_TYPE_802_1_Q = 1, >> + VLAN_TYPE_802_1_QBG = 2, >> + VLAN_TYPE_802_1_QBH = 4 >> +} VLANType; >> + >> +typedef enum { >> + BOOT_MODE_NOT_GOT = NUM_NOT_GOT, >> + BOOT_MODE_AUTOSTART = 1, >> + BOOT_MODE_NONE = 2 >> +} BootMode; >> + >> +struct BR_Prop { >> + int STP; >> + int delay; >> + char **port_names; >> + int port_num; >> +} ; >> + >> +struct Run_Prop { >> + int status; >> + BootMode boot_mode; >> +} ; >> + >> +struct VLAN_Prop_8021q { >> + int vlan_id; >> + char *parent; >> +} ; >> + >> +/* HP vlan standard, TBD */ >> +struct VLAN_Prop_8021qbg { >> + int invalid; >> +} ; >> + >> +/* Cisco and VMware vlan standard, TBD */ >> +struct VLAN_Prop_8021qbh { >> + int invalid; >> +} ; >> + >> +struct VLAN_Prop { >> + int vlan_type; >> + union { >> + struct VLAN_Prop_8021q prop_8021q; >> + struct VLAN_Prop_8021qbg prop_8021qbg; >> + struct VLAN_Prop_8021qbh prop_8021qbh; >> + } props; >> +} ; >> + >> +/* EthIface is logical devices include eth ports and bridges */ >> +struct EthIface { >> + char *name; >> + char *dep_ifname; /* parent dev name */ >> + char *attach_bridge; /* bridge the iface is attached to */ >> + char *mac; >> + EthType eth_type; >> + struct Run_Prop run_prop; >> + /* optional properties */ >> + struct BR_Prop *pbr_prop; >> + struct VLAN_Prop *pvlan_prop; >> +} ; >> + >> +struct EthIfacesList { >> + struct EthIface *pifaces[MAX_IFACE_NUM]; >> + int count; >> +} ; >> + >> +void eth_iface_init(struct EthIface *piface); >> +void eth_iface_add_br_prop(struct EthIface *piface); >> +void eth_iface_add_vlan_prop(struct EthIface *piface, int vlan_type); >> +void eth_iface_uninit(struct EthIface *piface); >> + >> +void eth_ifaceslist_init(struct EthIfacesList *plist); >> +void eth_ifaceslist_uninit(struct EthIfacesList *plist); >> +/* ppiface must be allocated from heap, to save code of struct duplication */ >> +int eth_ifaceslist_add(struct EthIfacesList *plist, struct EthIface **ppiface); >> +/* returned pointer is direct reference to a member in plist */ >> +struct EthIface *eth_ifaceslist_search(struct EthIfacesList *plist, >> + char *name); >> + >> +void eth_iface_print(struct EthIface *piface); >> +void eth_ifaceslist_print(struct EthIfacesList *plist); >> + >> +CMPIStatus get_host_ifaces(struct EthIfacesList *plist, >> + const CMPIBroker *broker, char *prefix); >> + >> +const char *EthIfaceListTOXML(char **ppxml, >> + struct EthIfacesList *plist, >> + int dump_all_flag); >> + >> +#endif >> diff --git a/libxkutil/network_parsing_test.c b/libxkutil/network_parsing_test.c >> new file mode 100644 >> index 0000000..593bfd0 >> --- /dev/null >> +++ b/libxkutil/network_parsing_test.c >> @@ -0,0 +1,61 @@ >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include >> +#include >> +#include >> + >> +#include "misc_util.h" >> +#include "device_parsing.h" >> +#include "network_parsing.h" >> + >> +static const CMPIBroker *broker; >> + >> +static long print_and_ret_time_stamp(void) >> +{ >> + struct timeval tv; >> + long ret; >> + gettimeofday(&tv, NULL); >> + ret = tv.tv_sec*1000 + tv.tv_usec/1000; >> + CU_DEBUG("time is [%ld] ms.", ret); >> + return ret; >> +} >> + >> +/* try retrieve all information, and then map them back to xml. */ >> +int main(int argc, char **argv) >> +{ >> + libvirt_cim_init(); >> + struct EthIfacesList *plist = NULL; >> + const char *msg = NULL; >> + char *genxml = NULL; >> + CMPIStatus s; >> + long start_time, end_time; >> + >> + SAFE_MALLOC(plist, sizeof(struct EthIfacesList)); >> + eth_ifaceslist_init(plist); >> + >> + start_time = print_and_ret_time_stamp(); >> + s = get_host_ifaces(plist, broker, "kvm"); >> + end_time = print_and_ret_time_stamp(); >> + CU_DEBUG("cost [%d]ms in discovering host network. Result:", >> + end_time - start_time); >> + eth_ifaceslist_print(plist); >> + >> + msg = EthIfaceListTOXML(&genxml, plist, 1); >> + CU_DEBUG("xml gen msg is %s. xml is:\n%s", msg, genxml); >> + SAFE_FREE(genxml); >> + >> + eth_ifaceslist_uninit(plist); >> + SAFE_FREE(plist); >> + return 0; >> +} >> diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c >> index 9a2ada9..001246a 100644 >> --- a/libxkutil/xmlgen.c >> +++ b/libxkutil/xmlgen.c >> @@ -830,7 +830,7 @@ static char *features_xml(xmlNodePtr root, struct domain *domain) >> return NULL; >> } >> >> -static char *tree_to_xml(xmlNodePtr root) >> +char *tree_to_xml(xmlNodePtr root) >> { >> xmlBufferPtr buffer = NULL; >> xmlSaveCtxtPtr savectx = NULL; >> diff --git a/libxkutil/xmlgen.h b/libxkutil/xmlgen.h >> index 743fc82..5d21a94 100644 >> --- a/libxkutil/xmlgen.h >> +++ b/libxkutil/xmlgen.h >> @@ -32,6 +32,8 @@ struct kv { >> const char *val; >> }; >> >> +char *tree_to_xml(xmlNodePtr root); >> + >> char *system_to_xml(struct domain *dominfo); >> char *device_to_xml(struct virt_device *dev); >> > > > _______________________________________________ > Libvirt-cim mailing list > Libvirt-cim at redhat.com > https://www.redhat.com/mailman/listinfo/libvirt-cim ------------------ Best Regards Wayne Xia 2012-01-27 ------------------------------------------------------------- ????Sharad Mishra ?????2012-01-27 02:37 ????List for discussion and development of libvirt CIM ??? ???Re: [Libvirt-cim] [PATCH v5] vlan extention - add function library for readonly usage Code looks good. I have marked some nits. Take a look. I have not yet applied the patch or done any testing. When do we see the actual provider? This patch is more of a backend/infrastructure. We will also need a CIM layer. -Sharad Mishra On Thu, 2012-01-26 at 04:04 +0800, xiaxia347work at 163.com wrote: > From: Wenchao Xia > > This patch contain 1 test program and 1 c file doing xml and structure > mapping. It expose some API to translate xml to device structure, in a similar > way to code in device_parsing.c. Also some other files are changed to let new > code use their internal functions. Type following Command in libxkutil > directory: > sudo CU_DEBUG=stdout .libs/network_parsing_test > could see what it have done. > > v5: calling libvirt API which employ netcf instead of using libnl. From git log > these API are available since 0.9.2, and this patch is tested with libvirt > 0.9.4. > > Signed-off-by: Wenchao Xia > --- > libxkutil/Makefile.am | 12 +- > libxkutil/misc_util.c | 10 +- > libxkutil/network_parsing.c | 665 ++++++++++++++++++++++++++++++++++++++ > libxkutil/network_parsing.h | 160 +++++++++ > libxkutil/network_parsing_test.c | 61 ++++ > libxkutil/xmlgen.c | 2 +- > libxkutil/xmlgen.h | 2 + > 7 files changed, 906 insertions(+), 6 deletions(-) > create mode 100644 libxkutil/network_parsing.c > create mode 100644 libxkutil/network_parsing.h > create mode 100644 libxkutil/network_parsing_test.c > > diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am > index f1adc03..c0e62eb 100644 > --- a/libxkutil/Makefile.am > +++ b/libxkutil/Makefile.am > @@ -4,12 +4,14 @@ AM_CFLAGS = $(CFLAGS_STRICT) \ > -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" > > noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ > - pool_parsing.h acl_parsing.h > + pool_parsing.h acl_parsing.h \ > + network_parsing.h > > lib_LTLIBRARIES = libxkutil.la > > libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ > - xmlgen.c infostore.c pool_parsing.c acl_parsing.c > + xmlgen.c infostore.c pool_parsing.c acl_parsing.c \ > + network_parsing.c > libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ > libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ > @LIBUUID_LIBS@ > @@ -19,3 +21,9 @@ noinst_PROGRAMS = xml_parse_test > xml_parse_test_SOURCES = xml_parse_test.c > xml_parse_test_LDADD = libxkutil.la \ > @LIBVIRT_LIBS@ > + > +noinst_PROGRAMS += network_parsing_test > + > +network_parsing_test_SOURCES = network_parsing_test.c > +network_parsing_test_LDADD = libxkutil.la \ > + @LIBVIRT_LIBS@ > diff --git a/libxkutil/misc_util.c b/libxkutil/misc_util.c > index 61893c3..1c18c33 100644 > --- a/libxkutil/misc_util.c > +++ b/libxkutil/misc_util.c > @@ -152,9 +152,13 @@ virConnectPtr connect_by_classname(const CMPIBroker *broker, > > uri = cn_to_uri(classname); > if (!uri) { > - cu_statusf(broker, s, > - CMPI_RC_ERR_FAILED, > - "Unable to generate URI from classname"); > + if (broker) { > + cu_statusf(broker, s, > + CMPI_RC_ERR_FAILED, > + "Unable to generate URI from classname"); > + } > + CU_DEBUG("Unable to generate URI from classname," > + " uri is %s.", uri); > return NULL; > } > > diff --git a/libxkutil/network_parsing.c b/libxkutil/network_parsing.c > new file mode 100644 > index 0000000..932000c > --- /dev/null > +++ b/libxkutil/network_parsing.c > @@ -0,0 +1,665 @@ > +/* > + * Copyright IBM Corp. 2012 > + * > + * Authors: > + * Wenchao Xia > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > + */ > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > + > +#include "misc_util.h" > +#include "xmlgen.h" > +#include "device_parsing.h" > +#include "network_parsing.h" > + > +#define XML_ERROR "Failed to allocate XML memory" > + > +static void vlan_prop_print(struct VLAN_Prop *pvlan_prop) > +{ > + struct VLAN_Prop_8021q *p_8021q; > + CMD_DEBUG(1, "--VLAN props: type %d.\n", > + pvlan_prop->vlan_type); > + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { > + p_8021q = &(pvlan_prop->props.prop_8021q); > + CMD_DEBUG(1, "----IEEE802.1.Q: id %d, parent %s.\n", > + p_8021q->vlan_id, p_8021q->parent); > + } > +} > + > +static void br_prop_print(struct BR_Prop *pbr_prop) > +{ > + int i = 0; > + CMD_DEBUG(1, "--Bridge props: stp %d, delay %d, port_num %d.\n", > + pbr_prop->STP, pbr_prop->delay, pbr_prop->port_num); > + if (pbr_prop->port_names != NULL) { > + CMD_DEBUG(1, "----Ports attached: "); > + while (i < pbr_prop->port_num) { > + CMD_DEBUG(1, " %s,", *(pbr_prop->port_names+i)); > + i++; > + } > + CMD_DEBUG(1, "\n"); > + } > +} > + > +void eth_iface_print(struct EthIface *piface) > +{ > + CMD_DEBUG(1, "Iface device: name %s.\n" > + "--Main Props: parent %s, attach to %s, mac %s," > + " status %d, boot_mode %d, iface type 0x%x.\n", > + piface->name, piface->dep_ifname, piface->attach_bridge, > + piface->mac, > + piface->run_prop.status, piface->run_prop.boot_mode, piface->eth_type); > + if (piface->pbr_prop != NULL) { > + br_prop_print(piface->pbr_prop); > + } > + if (piface->pvlan_prop != NULL) { > + vlan_prop_print(piface->pvlan_prop); > + } > + return; > +} > + > +void eth_ifaceslist_print(struct EthIfacesList *plist) > +{ > + int i = 0; > + CMD_DEBUG(1, "Have %d ifaces in the list:\n", plist->count); > + while (i < plist->count) { > + CMD_DEBUG(1, "%04d ", i); > + eth_iface_print(plist->pifaces[i]); > + i++; > + } > +} > + > +static void vlan_prop_init(struct VLAN_Prop *pvlan_prop, int vlan_type) > +{ > + struct VLAN_Prop_8021q *p_8021q; > + memset(pvlan_prop, 0, sizeof(struct VLAN_Prop)); > + pvlan_prop->vlan_type = vlan_type; > + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { > + p_8021q = &(pvlan_prop->props.prop_8021q); > + p_8021q->vlan_id = NUM_NOT_GOT; > + } > +} > + > +static void br_prop_init(struct BR_Prop *pbr_prop) > +{ > + memset(pbr_prop, 0, sizeof(struct BR_Prop)); > + pbr_prop->STP = NUM_NOT_GOT; > + pbr_prop->delay = NUM_NOT_GOT; > + pbr_prop->port_num = NUM_NOT_GOT; > +} > + > +void eth_iface_init(struct EthIface *piface) > +{ > + memset(piface, 0, sizeof(struct EthIface)); > + piface->eth_type = ETH_TYPE_NOT_GOT; > + piface->run_prop.status = NUM_NOT_GOT; > + piface->run_prop.boot_mode = BOOT_MODE_NOT_GOT; > + return; > +} > + > +void eth_iface_add_br_prop(struct EthIface *piface) > +{ > + if (piface->pbr_prop != NULL) { > + return; > + } > + SAFE_MALLOC(piface->pbr_prop, sizeof(struct BR_Prop)); > + br_prop_init(piface->pbr_prop); > +} > + > +void eth_iface_add_vlan_prop(struct EthIface *piface, int vlan_type) > +{ > + if (piface->pvlan_prop != NULL) { > + return; > + } > + SAFE_MALLOC(piface->pvlan_prop, sizeof(struct VLAN_Prop)); > + vlan_prop_init(piface->pvlan_prop, vlan_type); > +} > + > +static void vlan_prop_uninit(struct VLAN_Prop *pvlan_prop) > +{ > + struct VLAN_Prop_8021q *p_8021q; > + if (pvlan_prop == NULL) { > + return; > + } > + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { > + p_8021q = &(pvlan_prop->props.prop_8021q); > + SAFE_FREE(p_8021q->parent); > + } > +} > + > +static void br_prop_uninit(struct BR_Prop *pbr_prop) > +{ > + int i; > + if (pbr_prop == NULL) { > + return; > + } > + i = 0; > + if (pbr_prop->port_names != NULL) { > + while (i < pbr_prop->port_num) { > + SAFE_FREE(pbr_prop->port_names[i]); > + i++; > + } > + SAFE_FREE(pbr_prop->port_names); > + } > +} > + > +void eth_iface_uninit(struct EthIface *piface) > +{ > + if (piface == NULL) { > + return; > + } > + SAFE_FREE(piface->name); > + SAFE_FREE(piface->dep_ifname); > + SAFE_FREE(piface->attach_bridge); > + SAFE_FREE(piface->mac); > + br_prop_uninit(piface->pbr_prop); > + SAFE_FREE(piface->pbr_prop); > + vlan_prop_uninit(piface->pvlan_prop); > + SAFE_FREE(piface->pvlan_prop); > + return; > +} > + > +void eth_ifaceslist_init(struct EthIfacesList *plist) > +{ > + plist->count = 0; > +} > + > +void eth_ifaceslist_uninit(struct EthIfacesList *plist) > +{ > + struct EthIface **t; > + int i; > + if (plist->count <= 0) { > + return; > + } > + t = plist->pifaces; > + i = 0; > + while (i < plist->count) { > + if (*t != NULL) { > + eth_iface_uninit(*t); > + SAFE_FREE(*t); > + } > + t++; > + i++; > + } > + return; > +} > + > +int eth_ifaceslist_add(struct EthIfacesList *plist, struct EthIface **ppiface) > +{ > + if (plist->count >= MAX_IFACE_NUM) { > + CU_DEBUG("too much device found."); > + return 0; > + } > + plist->pifaces[plist->count] = *ppiface; > + *ppiface = NULL; > + plist->count++; > + return 1; > +} > + > +struct EthIface *eth_ifaceslist_search(struct EthIfacesList *plist, > + char *name) > +{ > + int i = 0; > + struct EthIface *piface = NULL; > + > + while (i < plist->count) { > + piface = plist->pifaces[i]; > + i++; > + if (piface != NULL) { > + if (0 == strcmp(piface->name, name)) { can we do "if (strcmp(piface->name, name) == 0) { " ? > + return piface; > + } > + } > + } > + return NULL; > +} > + > +/* Dummy function to suppress error message from libxml2 */ > +static void swallow_err_msg(void *ctx, const char *msg, ...) > +{ > + /* do nothing, just swallow the message. */ > +} > + > + > +static const char *gen_eth_xmlnode_iface(xmlNodePtr root, > + struct EthIface *piface, > + struct EthIfacesList *plist, > + int bridge_port_flag) > +{ > + const char *msg = NULL; > + xmlNodePtr temp_node1 = NULL, temp_node2 = NULL, temp_node3 = NULL; > + char *str, buf[16]; > + int i; > + struct EthIface *pifaceport; > + > + if (piface->name == NULL) { > + msg = "iface have no name.\n"; > + goto out; > + } > + /* netcfg have no xml for iface attatched to bridge */ > + if ((piface->attach_bridge != NULL) && (bridge_port_flag != 1)) { What are you trying to eliminate here? > + goto out; > + } > + > + temp_node1 = xmlNewChild(root, NULL, BAD_CAST "interface", NULL); > + if (temp_node1 == NULL) { > + msg = XML_ERROR; > + goto out; > + } > + xmlNewProp(temp_node1, BAD_CAST "name", BAD_CAST piface->name); > + if (piface->eth_type & ETH_TYPE_ETHER_ANY) { why do we require the above check? Can it be eliminated and just use the checks below? > + if (piface->eth_type & ETH_TYPE_ETHER_SUB_BRIDGE) { > + str = "bridge"; > + } else if (piface->eth_type & ETH_TYPE_ETHER_SUB_VLAN) { > + str = "vlan"; > + } else { > + str = "ethernet"; > + } > + xmlNewProp(temp_node1, BAD_CAST "type", BAD_CAST str); > + } > + > + if ((piface->pvlan_prop != NULL) && > + (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q)) { > + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "vlan", NULL); > + snprintf(buf, sizeof(buf), > + "%d", piface->pvlan_prop->props.prop_8021q.vlan_id); > + xmlNewProp(temp_node2, BAD_CAST "tag", BAD_CAST buf); > + temp_node3 = xmlNewChild(temp_node2, NULL, BAD_CAST "interface", NULL); > + xmlNewProp(temp_node3, BAD_CAST "name", > + BAD_CAST piface->pvlan_prop->props.prop_8021q.parent); > + } > + > + /* if it is attached to bridge, only above properties could be set */ > + if (bridge_port_flag == 1) { > + goto out; > + } > + > + if (piface->pbr_prop != NULL) { > + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "bridge", NULL); > + if (piface->pbr_prop->STP == 1) { > + snprintf(buf, sizeof(buf), "on"); > + } else { > + snprintf(buf, sizeof(buf), "off"); > + } > + xmlNewProp(temp_node2, BAD_CAST "stp", BAD_CAST buf); > + if (piface->pbr_prop->delay >= 0) { > + snprintf(buf, sizeof(buf), "%d", piface->pbr_prop->delay); > + xmlNewProp(temp_node2, BAD_CAST "delay", BAD_CAST buf); > + } > + if ((piface->pbr_prop->port_names != NULL) && > + (piface->pbr_prop->port_num > 0)) { > + for (i = 0; i < piface->pbr_prop->port_num; i++) { > + pifaceport = eth_ifaceslist_search(plist, > + piface->pbr_prop->port_names[i]); > + if (pifaceport == NULL) { > + CU_DEBUG("failed to find port %s of bridge %s in list.", > + piface->pbr_prop->port_names[i], piface->name); > + } else { > + gen_eth_xmlnode_iface(temp_node2, pifaceport, plist, 1); > + } > + } > + } > + } > + > + if (piface->run_prop.boot_mode == BOOT_MODE_AUTOSTART) { > + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "start", NULL); > + xmlNewProp(temp_node2, BAD_CAST "mode", BAD_CAST "onboot"); > + } else if (piface->run_prop.boot_mode == BOOT_MODE_NONE) { > + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "start", NULL); > + xmlNewProp(temp_node2, BAD_CAST "mode", BAD_CAST "none"); > + } > + if (piface->mac != NULL) { > + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "mac", NULL); > + xmlNewProp(temp_node2, BAD_CAST "address", BAD_CAST piface->mac); > + } > + > + out: > + return msg; > +} > + > +static const char *gen_eth_xmlnode(xmlNodePtr root, > + struct EthIfacesList *plist) > +{ > + const char *msg = NULL; > + int i = 0; > + struct EthIface *piface = NULL; > + > + while (i < plist->count) { > + piface = plist->pifaces[i]; > + i++; > + msg = gen_eth_xmlnode_iface(root, piface, plist, 0); > + if (msg != NULL) { > + goto out; > + } > + } > + > + out: > + return msg; > +} > + > +const char *EthIfaceListTOXML(char **ppxml, > + struct EthIfacesList *plist, > + int dump_all_flag) > +{ > + const char *msg = NULL; > + xmlNodePtr root = NULL; > + > + root = xmlNewNode(NULL, BAD_CAST "tmp"); > + if (root == NULL) { > + msg = "failed to create root node."; > + goto out; > + } > + msg = gen_eth_xmlnode(root, plist); > + if (msg == NULL) { > + if (dump_all_flag == 1) { > + *ppxml = tree_to_xml(root); > + } else { > + *ppxml = tree_to_xml(root->children); > + } > + } > + > + out: > + xmlFreeNode(root); > + return msg; > +} > + > +static int parse_eth_xmlnode(struct EthIfacesList *plist, xmlNode *inode, > + int status, char *attached) > +{ > + struct EthIface *piface = NULL; > + xmlNode *child1 = NULL, *child2 = NULL; > + char *temp = NULL, **ppchar; > + > + SAFE_MALLOC(piface, sizeof(struct EthIface)); > + eth_iface_init(piface); > + > + piface->name = get_attr_value(inode, "name"); > + piface->run_prop.status = status; > + if (attached != NULL) { > + piface->attach_bridge = strdup(attached); > + } > + temp = get_attr_value(inode, "type"); > + if (temp != NULL) { > + if (0 == strcmp(temp, "ethernet")) { can you change to if(strcmp() == 0) > + piface->eth_type = ETH_TYPE_ETHER_ANY; > + } > + if (0 == strcmp(temp, "bridge")) { > + piface->eth_type = ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_BRIDGE; > + } > + if (0 == strcmp(temp, "vlan")) { > + piface->eth_type = ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_VLAN; > + } > + SAFE_FREE(temp); > + } > + > + for (child1 = inode->children; child1 != NULL; child1 = child1->next) { > + if (XSTREQ(child1->name, "start")) { > + temp = get_attr_value(child1, "mode"); > + if (0 == strcmp(temp, "onboot")) { change as above > + piface->run_prop.boot_mode = BOOT_MODE_AUTOSTART; > + } > + if (0 == strcmp(temp, "none")) { > + piface->run_prop.boot_mode = BOOT_MODE_NONE; > + } > + SAFE_FREE(temp); > + } > + if (XSTREQ(child1->name, "mac")) { > + piface->mac = get_attr_value(child1, "address"); > + } > + if (XSTREQ(child1->name, "bridge")) { > + eth_iface_add_br_prop(piface); > + temp = get_attr_value(child1, "stp"); > + if (0 == strcmp(temp, "on")) { > + piface->pbr_prop->STP = 1; > + } > + if (0 == strcmp(temp, "off")) { > + piface->pbr_prop->STP = 0; > + } > + SAFE_FREE(temp); > + temp = get_attr_value(child1, "delay"); > + piface->pbr_prop->delay = strtol(temp, NULL, 10); > + SAFE_FREE(temp); > + } > + if (XSTREQ(child1->name, "bridge")) { > + eth_iface_add_br_prop(piface); > + temp = get_attr_value(child1, "stp"); > + if (0 == strcmp(temp, "on")) { > + piface->pbr_prop->STP = 1; > + } > + if (0 == strcmp(temp, "off")) { > + piface->pbr_prop->STP = 0; > + } > + SAFE_FREE(temp); > + temp = get_attr_value(child1, "delay"); > + piface->pbr_prop->delay = strtol(temp, NULL, 10); > + SAFE_FREE(temp); > + for (child2 = child1->children; child2 != NULL; > + child2 = child2->next) { > + if (XSTREQ(child2->name, "interface")) { > + if (piface->pbr_prop->port_names == NULL) { > + SAFE_CALLOC(piface->pbr_prop->port_names, > + MAX_IFACE_NUM, sizeof(char *)); > + piface->pbr_prop->port_num = 0; > + } > + ppchar = piface->pbr_prop->port_names + > + (piface->pbr_prop->port_num)++; > + *ppchar = get_attr_value(child2, "name"); > + parse_eth_xmlnode(plist, child2, status, piface->name); > + } > + } > + } > + if (XSTREQ(child1->name, "vlan")) { > + eth_iface_add_vlan_prop(piface, VLAN_TYPE_802_1_Q); > + temp = get_attr_value(child1, "tag"); > + piface->pvlan_prop->props.prop_8021q.vlan_id = > + strtol(temp, NULL, 10); > + SAFE_FREE(temp); > + for (child2 = child1->children; child2 != NULL; > + child2 = child2->next) { > + if (XSTREQ(child2->name, "interface")) { > + piface->pvlan_prop->props.prop_8021q.parent = > + get_attr_value(child2, "name"); > + piface->dep_ifname = > + get_attr_value(child2, "name"); > + } > + } > + } > + } > + > + eth_ifaceslist_add(plist, &piface); > + return 1; > +} > + > +static const char *XMLToEthIfaceList(struct EthIfacesList *plist, > + const char *xml, > + int status) > +{ > + xmlDoc *xmldoc; > + xmlXPathContext *xpathCtx; > + xmlXPathObject *xpathObj; > + xmlChar *xpathstr; > + xmlNode **dev_nodes = NULL; > + xmlNodeSet *nsv = NULL; > + int count = 0; > + int len, devidx; > + const char *msg = NULL; > + > + len = strlen(xml) + 1; > + xpathstr = (xmlChar *)"/interface"; > + > + xmlSetGenericErrorFunc(NULL, swallow_err_msg); > + if ((xmldoc = xmlParseMemory(xml, len)) == NULL) { > + msg = "failed to get xmldoc."; > + goto err1; > + } > + > + if ((xpathCtx = xmlXPathNewContext(xmldoc)) == NULL) { > + msg = "failed to get pathCtx"; > + goto err2; > + } > + > + if ((xpathObj = xmlXPathEvalExpression(xpathstr, xpathCtx)) > + == NULL) { > + msg = "failed to get xpathObj"; > + goto err3; > + } > + > + nsv = xpathObj->nodesetval; > + if (nsv == NULL) { > + msg = "failed to get nodesetval."; > + goto out; > + } > + > + dev_nodes = nsv->nodeTab; > + count = nsv->nodeNr; > + > + if (count <= 0) { > + msg = "nodesetval have less that 1 values."; > + goto out; > + } > + > + for (devidx = 0; devidx < count; devidx++) { > + parse_eth_xmlnode(plist, dev_nodes[devidx], status, NULL); > + } > + > + out: > + xmlSetGenericErrorFunc(NULL, NULL); > + xmlXPathFreeObject(xpathObj); > + > + err3: > + xmlXPathFreeContext(xpathCtx); > + err2: > + xmlFreeDoc(xmldoc); > + err1: > + return msg; > +} > + > +CMPIStatus get_host_ifaces(struct EthIfacesList *plist, > + const CMPIBroker *broker, char *prefix) > +{ > + virConnectPtr conn = NULL; > + virInterfacePtr iface; > + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; > + int num, listnum, i; > + char **names = NULL; > + char *dump = NULL; > + int flags = 0; > + const char *msg; > + > + conn = connect_by_classname(broker, prefix, &s); > + if (conn == NULL) { > + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, "connect failed."); > + goto out; > + } > + > + /* list defined interfaces*/ > + num = virConnectNumOfDefinedInterfaces(conn); > + if (num < 0) { > + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, > + "failed to find number of defined interfaces."); > + goto out; > + } > + names = malloc(num * sizeof(char *)); > + listnum = virConnectListDefinedInterfaces(conn, names, num); > + if (listnum < 0) { > + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, > + "failed to list names of defined interfaces."); > + goto out; > + } > + CU_DEBUG("%d defined ifaces found from libvirt API.\n", listnum); > + > + flags |= VIR_INTERFACE_XML_INACTIVE; > + for (i = 0; i < listnum; i++) { > + iface = virInterfaceLookupByName(conn, names[i]); > + if (!iface) { > + CU_DEBUG("failed to look up %s.\n", names[i]); > + SAFE_FREE(names[i]); > + continue; > + } > + SAFE_FREE(names[i]); > + dump = virInterfaceGetXMLDesc(iface, flags); > + CU_DEBUG("defined interface %d xml:\n%s", i, dump); > + msg = XMLToEthIfaceList(plist, dump, 0); > + if (msg != NULL) { > + CU_DEBUG("failed parsing eth xml, msg is: %s.", msg); > + } > + SAFE_FREE(dump); > + virInterfaceFree(iface); > + } > + SAFE_FREE(names); > + > + /* list active interfaces*/ > + num = virConnectNumOfInterfaces(conn); > + if (num < 0) { > + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, > + "failed to find number of active interfaces."); > + goto out; > + } > + names = malloc(num * sizeof(char *)); > + > + listnum = virConnectListInterfaces(conn, names, num); > + if (listnum < 0) { > + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, > + "failed to list names of active interfacess."); > + goto out; > + } > + CU_DEBUG("%d active ifaces found from libvirt API.\n", listnum); > + > + flags |= VIR_INTERFACE_XML_INACTIVE; > + for (i = 0; i < listnum; i++) { > + iface = virInterfaceLookupByName(conn, names[i]); > + if (!iface) { > + CU_DEBUG("failed to look up %s.\n", names[i]); > + SAFE_FREE(names[i]); > + continue; > + } > + SAFE_FREE(names[i]); > + dump = virInterfaceGetXMLDesc(iface, flags); > + CU_DEBUG("active interface %d xml:\n%s", i, dump); > + msg = XMLToEthIfaceList(plist, dump, 1); > + if (msg != NULL) { > + CU_DEBUG("failed parsing eth xml, msg is: %s.", msg); > + } > + SAFE_FREE(dump); > + virInterfaceFree(iface); > + } > + s.rc = CMPI_RC_OK; > + > + out: > + virConnectClose(conn); > + SAFE_FREE(names); > + return s; > +} > +/* > + * Local Variables: > + * mode: C > + * c-set-style: "K&R" > + * tab-width: 8 > + * c-basic-offset: 8 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/libxkutil/network_parsing.h b/libxkutil/network_parsing.h > new file mode 100644 > index 0000000..bbfe729 > --- /dev/null > +++ b/libxkutil/network_parsing.h > @@ -0,0 +1,160 @@ > +/* > + * Copyright IBM Corp. 2012 > + * > + * Authors: > + * Wenchao Xia > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + */ > + > +#ifndef NETWORK_PARSING_H > +#define NETWORK_PARSING_H > + > +#include > +#include > +#include > + > +/* value defines */ > +#define MAX_IFACE_NUM 4096 > + > +#define NUM_NOT_GOT -1 > + > +#define ETH_TYPE_BASE_MASK 0xff00 > +#define ETH_TYPE_SUB_MASK 0x00ff > + > +#define CMD_DEBUG_LEVEL 2 > + > +/* macro functions */ > +#define CMD_DEBUG(lvl, fmt, args...) do { \ > + if (CMD_DEBUG_LEVEL && (lvl) <= CMD_DEBUG_LEVEL) { \ > + debug_print(fmt, ##args); \ > + } \ > +} while (0) > + > +#define SAFE_MALLOC(p, size) \ > +{ \ > + (p) = malloc((size)); \ > + if ((p) == NULL) { \ > + CU_DEBUG("malloc failed."); \ > + } \ > +} > + > +#define SAFE_CALLOC(p, nmen, size) \ > +{ \ > + (p) = calloc((nmen), (size)); \ > + if ((p) == NULL) { \ > + CU_DEBUG("calloc failed."); \ > + } \ > +} > + > +#define SAFE_FREE(p) {free(p); (p) = NULL; } > + > +#define RECORD_MSG(broker, ps, rc, fmt, args...) do { \ > + CU_DEBUG(fmt, ##args); \ > + if (broker) { \ > + cu_statusf((broker), (ps), (rc), fmt, ##args); \ > + } \ > +} while (0) > + > +typedef enum { > + ETH_TYPE_NOT_GOT = 0x0000, > + ETH_TYPE_ETHER_ANY = 0x0100, > + ETH_TYPE_ETHER_SUB_PHYSICAL = 0x0001, > + ETH_TYPE_ETHER_SUB_BRIDGE = 0x0002, > + ETH_TYPE_ETHER_SUB_VLAN = 0x0004 > +} EthType; > + > +typedef enum { > + VLAN_TYPE_NOT_GOT = NUM_NOT_GOT, > + VLAN_TYPE_802_1_Q = 1, > + VLAN_TYPE_802_1_QBG = 2, > + VLAN_TYPE_802_1_QBH = 4 > +} VLANType; > + > +typedef enum { > + BOOT_MODE_NOT_GOT = NUM_NOT_GOT, > + BOOT_MODE_AUTOSTART = 1, > + BOOT_MODE_NONE = 2 > +} BootMode; > + > +struct BR_Prop { > + int STP; > + int delay; > + char **port_names; > + int port_num; > +} ; > + > +struct Run_Prop { > + int status; > + BootMode boot_mode; > +} ; > + > +struct VLAN_Prop_8021q { > + int vlan_id; > + char *parent; > +} ; > + > +/* HP vlan standard, TBD */ > +struct VLAN_Prop_8021qbg { > + int invalid; > +} ; > + > +/* Cisco and VMware vlan standard, TBD */ > +struct VLAN_Prop_8021qbh { > + int invalid; > +} ; > + > +struct VLAN_Prop { > + int vlan_type; > + union { > + struct VLAN_Prop_8021q prop_8021q; > + struct VLAN_Prop_8021qbg prop_8021qbg; > + struct VLAN_Prop_8021qbh prop_8021qbh; > + } props; > +} ; > + > +/* EthIface is logical devices include eth ports and bridges */ > +struct EthIface { > + char *name; > + char *dep_ifname; /* parent dev name */ > + char *attach_bridge; /* bridge the iface is attached to */ > + char *mac; > + EthType eth_type; > + struct Run_Prop run_prop; > + /* optional properties */ > + struct BR_Prop *pbr_prop; > + struct VLAN_Prop *pvlan_prop; > +} ; > + > +struct EthIfacesList { > + struct EthIface *pifaces[MAX_IFACE_NUM]; > + int count; > +} ; > + > +void eth_iface_init(struct EthIface *piface); > +void eth_iface_add_br_prop(struct EthIface *piface); > +void eth_iface_add_vlan_prop(struct EthIface *piface, int vlan_type); > +void eth_iface_uninit(struct EthIface *piface); > + > +void eth_ifaceslist_init(struct EthIfacesList *plist); > +void eth_ifaceslist_uninit(struct EthIfacesList *plist); > +/* ppiface must be allocated from heap, to save code of struct duplication */ > +int eth_ifaceslist_add(struct EthIfacesList *plist, struct EthIface **ppiface); > +/* returned pointer is direct reference to a member in plist */ > +struct EthIface *eth_ifaceslist_search(struct EthIfacesList *plist, > + char *name); > + > +void eth_iface_print(struct EthIface *piface); > +void eth_ifaceslist_print(struct EthIfacesList *plist); > + > +CMPIStatus get_host_ifaces(struct EthIfacesList *plist, > + const CMPIBroker *broker, char *prefix); > + > +const char *EthIfaceListTOXML(char **ppxml, > + struct EthIfacesList *plist, > + int dump_all_flag); > + > +#endif > diff --git a/libxkutil/network_parsing_test.c b/libxkutil/network_parsing_test.c > new file mode 100644 > index 0000000..593bfd0 > --- /dev/null > +++ b/libxkutil/network_parsing_test.c > @@ -0,0 +1,61 @@ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > + > +#include "misc_util.h" > +#include "device_parsing.h" > +#include "network_parsing.h" > + > +static const CMPIBroker *broker; > + > +static long print_and_ret_time_stamp(void) > +{ > + struct timeval tv; > + long ret; > + gettimeofday(&tv, NULL); > + ret = tv.tv_sec*1000 + tv.tv_usec/1000; > + CU_DEBUG("time is [%ld] ms.", ret); > + return ret; > +} > + > +/* try retrieve all information, and then map them back to xml. */ > +int main(int argc, char **argv) > +{ > + libvirt_cim_init(); > + struct EthIfacesList *plist = NULL; > + const char *msg = NULL; > + char *genxml = NULL; > + CMPIStatus s; > + long start_time, end_time; > + > + SAFE_MALLOC(plist, sizeof(struct EthIfacesList)); > + eth_ifaceslist_init(plist); > + > + start_time = print_and_ret_time_stamp(); > + s = get_host_ifaces(plist, broker, "kvm"); > + end_time = print_and_ret_time_stamp(); > + CU_DEBUG("cost [%d]ms in discovering host network. Result:", > + end_time - start_time); > + eth_ifaceslist_print(plist); > + > + msg = EthIfaceListTOXML(&genxml, plist, 1); > + CU_DEBUG("xml gen msg is %s. xml is:\n%s", msg, genxml); > + SAFE_FREE(genxml); > + > + eth_ifaceslist_uninit(plist); > + SAFE_FREE(plist); > + return 0; > +} > diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c > index 9a2ada9..001246a 100644 > --- a/libxkutil/xmlgen.c > +++ b/libxkutil/xmlgen.c > @@ -830,7 +830,7 @@ static char *features_xml(xmlNodePtr root, struct domain *domain) > return NULL; > } > > -static char *tree_to_xml(xmlNodePtr root) > +char *tree_to_xml(xmlNodePtr root) > { > xmlBufferPtr buffer = NULL; > xmlSaveCtxtPtr savectx = NULL; > diff --git a/libxkutil/xmlgen.h b/libxkutil/xmlgen.h > index 743fc82..5d21a94 100644 > --- a/libxkutil/xmlgen.h > +++ b/libxkutil/xmlgen.h > @@ -32,6 +32,8 @@ struct kv { > const char *val; > }; > > +char *tree_to_xml(xmlNodePtr root); > + > char *system_to_xml(struct domain *dominfo); > char *device_to_xml(struct virt_device *dev); > _______________________________________________ Libvirt-cim mailing list Libvirt-cim at redhat.com https://www.redhat.com/mailman/listinfo/libvirt-cim From eblima at linux.vnet.ibm.com Mon Jan 30 23:57:48 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Mon, 30 Jan 2012 21:57:48 -0200 Subject: [Libvirt-cim] [PATCH 1/4] FilterEntry: Change 'Priority' property type In-Reply-To: <1327967871-24219-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1327967871-24219-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1327967871-24219-2-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" According to libvirt network filters specification, since version 0.9.8, priority values can accept negative values within the range -1000 to 1000. Thus the FilterEntry property value type went from unsigned int to signed int. Signed-off-by: Eduardo Lima (Etrunko) --- schema/FilterEntry.mof | 18 +++++++++--------- src/Virt_FilterEntry.c | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/schema/FilterEntry.mof b/schema/FilterEntry.mof index b51150c..f60abae 100644 --- a/schema/FilterEntry.mof +++ b/schema/FilterEntry.mof @@ -30,11 +30,11 @@ class KVM_Hdr8021Filter : CIM_Hdr8021Filter "the rule will be, instantiated relative to other rules. " "Rules with lower value will be instantiated and therefore " "evaluated before rules with higher value. Valid values are " - "in the range of 0 to 1000. If this attribute is not " + "in the range of -1000 to 1000. If this attribute is not " "provided, the value 500 will automatically be assigned."), - MinValue(0), + MinValue(-1000), MaxValue(1000)] - uint16 Priority = 500; + sint16 Priority = 500; }; [Provider("cmpi::Virt_FilterEntry")] @@ -68,11 +68,11 @@ class KVM_IPHeadersFilter : CIM_IPHeadersFilter "the rule will be, instantiated relative to other rules. " "Rules with lower value will be instantiated and therefore " "evaluated before rules with higher value. Valid values are " - "in the range of 0 to 1000. If this attribute is not " + "in the range of -1000 to 1000. If this attribute is not " "provided, the value 500 will automatically be assigned."), - MinValue(0), + MinValue(-1000), MaxValue(1000)] - uint16 Priority = 500; + sint16 Priority = 500; }; [Provider("cmpi::Virt_FilterEntry")] @@ -98,9 +98,9 @@ class KVM_FilterEntry : CIM_FilterEntry "the rule will be, instantiated relative to other rules. " "Rules with lower value will be instantiated and therefore " "evaluated before rules with higher value. Valid values are " - "in the range of 0 to 1000. If this attribute is not " + "in the range of -1000 to 1000. If this attribute is not " "provided, the value 500 will automatically be assigned."), - MinValue(0), + MinValue(-1000), MaxValue(1000)] - uint16 Priority = 500; + sint16 Priority = 500; }; diff --git a/src/Virt_FilterEntry.c b/src/Virt_FilterEntry.c index 16b211e..a4fa4cd 100644 --- a/src/Virt_FilterEntry.c +++ b/src/Virt_FilterEntry.c @@ -554,7 +554,7 @@ static CMPIInstance *convert_rule_to_instance( CMSetProperty(inst, "Direction", (CMPIValue *)&direction, CMPI_uint16); priority = convert_priority(rule->priority); - CMSetProperty(inst, "Priority", (CMPIValue *)&priority, CMPI_uint16); + CMSetProperty(inst, "Priority", (CMPIValue *)&priority, CMPI_sint16); if (convert_f) convert_f(rule, inst, broker); -- 1.7.7.6 From eblima at linux.vnet.ibm.com Mon Jan 30 23:57:47 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Mon, 30 Jan 2012 21:57:47 -0200 Subject: [Libvirt-cim] [PATCH 0/4] Update Filter{Entry,List} providers Message-ID: <1327967871-24219-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" These changes are necessary due to recent changes in the libvirt network filters specification. Cimtests were also updated to match these changes. http://libvirt.org/formatnwfilter.html Eduardo Lima (Etrunko) (4): FilterEntry: Change 'Priority' property type FilterList: Add 'Priority' property FilterEntry: Update action property FilterEntry: Accept protocol id string values libxkutil/acl_parsing.c | 2 + libxkutil/acl_parsing.h | 1 + schema/FilterEntry.mof | 26 ++++++++++++------------ schema/FilterList.mof | 9 ++++++++ src/Makefile.am | 4 +- src/Virt_FilterEntry.c | 49 +++++++++++++++++++++++++++++++++++----------- src/Virt_FilterEntry.h | 6 +++++ src/Virt_FilterList.c | 5 +++- 8 files changed, 74 insertions(+), 28 deletions(-) -- 1.7.7.6 From eblima at linux.vnet.ibm.com Mon Jan 30 23:57:49 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Mon, 30 Jan 2012 21:57:49 -0200 Subject: [Libvirt-cim] [PATCH 2/4] FilterList: Add 'Priority' property In-Reply-To: <1327967871-24219-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1327967871-24219-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1327967871-24219-3-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" According to libvirt network filter specification, since verstion 0.9.8, filter lists can be assigned priorities. Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/acl_parsing.c | 2 ++ libxkutil/acl_parsing.h | 1 + schema/FilterList.mof | 9 +++++++++ src/Makefile.am | 4 ++-- src/Virt_FilterEntry.c | 11 ++++------- src/Virt_FilterEntry.h | 6 ++++++ src/Virt_FilterList.c | 5 ++++- 7 files changed, 28 insertions(+), 10 deletions(-) diff --git a/libxkutil/acl_parsing.c b/libxkutil/acl_parsing.c index 9c4b4b2..2930928 100644 --- a/libxkutil/acl_parsing.c +++ b/libxkutil/acl_parsing.c @@ -134,6 +134,7 @@ void cleanup_filter(struct acl_filter *filter) free(filter->uuid); free(filter->name); free(filter->chain); + free(filter->priority); for (i = 0; i < filter->rule_ct; i++) cleanup_rule(filter->rules[i]); @@ -345,6 +346,7 @@ static int parse_acl_filter(xmlNode *fnode, struct acl_filter *filter) goto err; filter->chain = get_attr_value(fnode, "chain"); + filter->priority = get_attr_value(fnode, "priority"); for (child = fnode->children; child != NULL; child = child->next) { if (XSTREQ(child->name, "uuid")) { diff --git a/libxkutil/acl_parsing.h b/libxkutil/acl_parsing.h index 5b99175..5abcb02 100644 --- a/libxkutil/acl_parsing.h +++ b/libxkutil/acl_parsing.h @@ -148,6 +148,7 @@ struct acl_filter { char *uuid; char *name; char *chain; + char *priority; struct acl_rule **rules; int rule_ct; diff --git a/schema/FilterList.mof b/schema/FilterList.mof index a98c14d..7339db6 100644 --- a/schema/FilterList.mof +++ b/schema/FilterList.mof @@ -1,4 +1,13 @@ // Copyright IBM Corp. 2011 class KVM_FilterList : CIM_FilterList { + [Description("The priority of the filter controls the order in which " + "the filter will be, instantiated relative to other filters. " + "Filters with lower value will be instantiated and therefore " + "evaluated before rules with higher value. Valid values are " + "in the range of -1000 to 1000. If this attribute is not " + "provided, the value 500 will automatically be assigned."), + MinValue(-1000), + MaxValue(1000)] + sint16 Priority = 500; }; diff --git a/src/Makefile.am b/src/Makefile.am index c28dc9a..3f90926 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -255,9 +255,9 @@ libVirt_FilterEntry_la_DEPENDENCIES = libVirt_HostSystem.la libVirt_FilterEntry_la_SOURCES = Virt_FilterEntry.c libVirt_FilterEntry_la_LIBADD = -lVirt_HostSystem -libVirt_FilterList_la_DEPENDENCIES = libVirt_HostSystem.la +libVirt_FilterList_la_DEPENDENCIES = libVirt_HostSystem.la libVirt_FilterEntry.la libVirt_FilterList_la_SOURCES = Virt_FilterList.c -libVirt_FilterList_la_LIBADD = -lVirt_HostSystem +libVirt_FilterList_la_LIBADD = -lVirt_HostSystem -lVirt_FilterEntry libVirt_EntriesInFilterList_la_DEPENDENCIES = libVirt_FilterEntry.la libVirt_FilterList.la libVirt_EntriesInFilterList_la_SOURCES = Virt_EntriesInFilterList.c diff --git a/src/Virt_FilterEntry.c b/src/Virt_FilterEntry.c index a4fa4cd..c058b5e 100644 --- a/src/Virt_FilterEntry.c +++ b/src/Virt_FilterEntry.c @@ -192,15 +192,12 @@ static int convert_direction(const char *s) return direction; } -static int convert_priority(const char *s) +int convert_priority(const char *s) { - int priority = 0; - - if (s != NULL) { - priority = atoi(s); - } + if (s == NULL) + return 0; - return priority; + return atoi(s); } static int convert_action(const char *s) diff --git a/src/Virt_FilterEntry.h b/src/Virt_FilterEntry.h index 2fe17c4..a30f46d 100644 --- a/src/Virt_FilterEntry.h +++ b/src/Virt_FilterEntry.h @@ -72,6 +72,12 @@ CMPIStatus instance_from_rule( struct acl_rule *rule, CMPIInstance **instance); +/** + * Convert a string representing the priority to corresponding integer value + * + * @param s A pointer to a string representing the priority + */ +int convert_priority(const char *s); #endif /* diff --git a/src/Virt_FilterList.c b/src/Virt_FilterList.c index 5b1b6e8..9b5dbae 100644 --- a/src/Virt_FilterList.c +++ b/src/Virt_FilterList.c @@ -31,6 +31,7 @@ #include "Virt_FilterList.h" #include "Virt_HostSystem.h" +#include "Virt_FilterEntry.h" const static CMPIBroker *_BROKER; @@ -44,7 +45,7 @@ static CMPIInstance *convert_filter_to_instance( CMPIInstance *inst = NULL; const char *sys_name = NULL; const char *sys_ccname = NULL; - int direction = 0; + int direction = 0, priority; inst = get_typed_instance(broker, CLASSNAME(reference), @@ -77,6 +78,8 @@ static CMPIInstance *convert_filter_to_instance( CMPI_chars); CMSetProperty(inst, "Direction", (CMPIValue *)&direction, CMPI_uint16); + priority = convert_priority(filter->priority); + CMSetProperty(inst, "Priority", (CMPIValue *)&priority, CMPI_sint16); out: return inst; } -- 1.7.7.6 From eblima at linux.vnet.ibm.com Mon Jan 30 23:57:50 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Mon, 30 Jan 2012 21:57:50 -0200 Subject: [Libvirt-cim] [PATCH 3/4] FilterEntry: Update action property In-Reply-To: <1327967871-24219-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1327967871-24219-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1327967871-24219-4-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" According to libvirt network filters specification, new values have been added: Since 0.9.0: - reject Since 0.9.7: - return - continue Signed-off-by: Eduardo Lima (Etrunko) --- schema/FilterEntry.mof | 8 ++++---- src/Virt_FilterEntry.c | 10 ++++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/schema/FilterEntry.mof b/schema/FilterEntry.mof index f60abae..b5f695f 100644 --- a/schema/FilterEntry.mof +++ b/schema/FilterEntry.mof @@ -6,8 +6,8 @@ class KVM_Hdr8021Filter : CIM_Hdr8021Filter "This defines whether the action should be to forward or " "deny traffic meeting the match condition specified in " "this filter." ), - ValueMap { "1", "2" }, - Values { "Permit", "Deny" }] + ValueMap { "1", "2", "3", "4", "5" }, + Values { "Permit", "Deny", "Reject", "Return", "Continue" }] uint16 Action; [Description("This defines whether the Filter is used for input, " @@ -44,8 +44,8 @@ class KVM_IPHeadersFilter : CIM_IPHeadersFilter "This defines whether the action should be to forward or " "deny traffic meeting the match condition specified in " "this filter." ), - ValueMap { "1", "2" }, - Values { "Permit", "Deny" }] + ValueMap { "1", "2", "3", "4", "5" }, + Values { "Permit", "Deny", "Reject", "Return", "Continue" }] uint16 Action; [Description("This defines whether the Filter is used for input, " diff --git a/src/Virt_FilterEntry.c b/src/Virt_FilterEntry.c index c058b5e..2ff354a 100644 --- a/src/Virt_FilterEntry.c +++ b/src/Virt_FilterEntry.c @@ -202,13 +202,19 @@ int convert_priority(const char *s) static int convert_action(const char *s) { - enum {NONE=0, ACCEPT, DENY} action = NONE; + enum {NONE=0, ACCEPT, DENY, REJECT, RETURN, CONTINUE} action = NONE; if (s != NULL) { if (STREQC(s, "accept")) action = ACCEPT; - else if (STREQC(s, "drop") || STREQC(s, "reject")) + else if (STREQC(s, "drop")) action = DENY; + else if (STREQC(s, "reject")) + action = REJECT; + else if (STREQC(s, "return")) + action = RETURN; + else if (STREQC(s, "continue")) + action = CONTINUE; } return action; } -- 1.7.7.6 From eblima at linux.vnet.ibm.com Mon Jan 30 23:57:51 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Mon, 30 Jan 2012 21:57:51 -0200 Subject: [Libvirt-cim] [PATCH 4/4] FilterEntry: Accept protocol id string values In-Reply-To: <1327967871-24219-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1327967871-24219-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1327967871-24219-5-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" The HdrProtocolID8021 property expects an unsigned int value, while libvirt network filters specification allows the corresponding value for this property (protocolid) to be written as a string (ipv4, ipv6, arp, rarp). The corresponding values for the protocolid strings can be found in: http://www.iana.org/assignments/ethernet-numbers Signed-off-by: Eduardo Lima (Etrunko) --- src/Virt_FilterEntry.c | 26 ++++++++++++++++++++++++-- 1 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/Virt_FilterEntry.c b/src/Virt_FilterEntry.c index 2ff354a..126615b 100644 --- a/src/Virt_FilterEntry.c +++ b/src/Virt_FilterEntry.c @@ -219,6 +219,24 @@ static int convert_action(const char *s) return action; } +static unsigned long convert_protocol_id(const char *s) +{ + enum {NONE = 0, IPV4 = 2048, ARP = 2054, RARP = 32821, IPV6 = 34525} id = NONE; + + if (s != NULL) { + if (STREQC(s, "ipv4")) + id = IPV4; + else if (STREQC(s, "arp")) + id = ARP; + else if (STREQC(s, "rarp")) + id = RARP; + else if (STREQC(s, "ipv6")) + id = IPV6; + } + + return id; +} + static void convert_mac_rule_to_instance( struct acl_rule *rule, CMPIInstance *inst, @@ -265,8 +283,12 @@ static void convert_mac_rule_to_instance( (CMPIValue *)&array, CMPI_uint8A); if (rule->var.mac.protocol_id != NULL) { - unsigned long n = strtoul(rule->var.mac.protocol_id, - NULL, 16); + unsigned long n = convert_protocol_id(rule->var.mac.protocol_id); + + /* Unknown protocolid string. Try converting from hexadecimal value */ + if (n == 0) + n = strtoul(rule->var.mac.protocol_id, NULL, 16); + CMSetProperty(inst, "HdrProtocolID8021", (CMPIValue *)&n, CMPI_uint16); } -- 1.7.7.6 From eblima at linux.vnet.ibm.com Mon Jan 30 23:59:28 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Mon, 30 Jan 2012 21:59:28 -0200 Subject: [Libvirt-cim] [PATCH] [TEST] Update FilterList tests and helper Message-ID: <1327967968-26939-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" According to recent changes in FilterList and FilterEntry providers. 03_create.py: - Creation and deletion of AppliedFilterList instance - Deletion of NestedFilterList instance - Deletion of FilterList instance helper.py: - Removed warning about Deprecated use of lxml functionality - New filter rule actions - Match protocol id Signed-off-by: Eduardo Lima (Etrunko) --- suites/libvirt-cim/cimtest/FilterList/03_create.py | 35 +++++++++++++--- suites/libvirt-cim/cimtest/FilterList/helper.py | 42 +++++++++++++++++--- 2 files changed, 64 insertions(+), 13 deletions(-) diff --git a/suites/libvirt-cim/cimtest/FilterList/03_create.py b/suites/libvirt-cim/cimtest/FilterList/03_create.py index e828e92..551a01f 100644 --- a/suites/libvirt-cim/cimtest/FilterList/03_create.py +++ b/suites/libvirt-cim/cimtest/FilterList/03_create.py @@ -38,6 +38,9 @@ from VirtLib.utils import run_remote sup_types = ["KVM",] domain = None +flist_name = None +nested_name = None +applied_name = None def get_filter_inst_and_inst_name(name): try: @@ -89,6 +92,7 @@ def create_filter_list(name): # A NestedFilterList instance will add the "clean-traffic" filter # as an entry of the newly created FilterList + global nested_name logger.info("Creating NestedFilterList instance") nested_name = test.CreateFilterListInstance(None, "KVM_NestedFilterList", {"Antecedent":flist_name, @@ -125,8 +129,11 @@ def get_nwport_inst_and_inst_name(domain_name): def cleanup(): try: - # Destroy filter list - test.wbem.DeleteInstance(flist_name) + # Destroy filter list instances + for n in [applied_name, nested_name, flist_name]: + if n is not None: + logger.info("Deleting instance %s", n) + test.wbem.DeleteInstance(n) except Exception, e: logger.error("Error deleting filter list: %s", e) @@ -165,15 +172,29 @@ def main(): # An AppliedFilterList Instance will apply the filter to the network # port of the defined domain - test.CreateFilterListInstance(None, "KVM_AppliedFilterList", - {"Antecedent":nwport_name, - "Dependent":flist_name}) + global applied_name + logger.info ("Creating AppliedFilterList instance") + applied_name = test.CreateFilterListInstance(None, "KVM_AppliedFilterList", + {"Antecedent":nwport_name, + "Dependent":flist_name}) + logger.info("Got AppliedFilterList name '%s'", applied_name) + #applied = test.GetInstance(applied_name) + #logger.info("Got AppliedFilterList '%s'", applied) + + # Check results + filterref = test.libvirt_applied_filter_lists(domain_name)[0] + rule = helper.FilterRule(filterref) + if rule.filter != test_flist: + raise Exception("AppliedFilterList name '%s' does not match expected '%s'", + rule.filter, test_flist) + + test.cim_applied_filter_lists(domain_name) + logger.info("AppliedFilterList created succesfully") + result = PASS except Exception, e: logger.error("Caught exception: %s", e) result = FAIL - # Check results - # Cleanup cleanup() diff --git a/suites/libvirt-cim/cimtest/FilterList/helper.py b/suites/libvirt-cim/cimtest/FilterList/helper.py index 9ae2f62..5202fa6 100644 --- a/suites/libvirt-cim/cimtest/FilterList/helper.py +++ b/suites/libvirt-cim/cimtest/FilterList/helper.py @@ -252,7 +252,7 @@ class FilterListTest(BaseTestObject): d = {} for f in filters: root = self.libvirt_filter_dumpxml(f[0]) - if not root: + if root is None: return None d[f] = root @@ -307,6 +307,22 @@ class FilterListTest(BaseTestObject): return self.Associators(_inst_name, result_class="CIM_FilterEntryBase") # cim_entries_in_filter_list + + def libvirt_applied_filter_lists(self, dom_name): + cmd = "virsh -q -c %s dumpxml %s 2>/dev/null" % (self.uri, dom_name) + ret, dom_xml = run_remote(self.server, cmd) + if ret: + logger.error("Error retrieving domain xml for %s", dom_name) + return None + + xdoc = etree.fromstring(dom_xml) + filter_list = xdoc.xpath("/domain/devices/interface/filterref") + return filter_list + # libvirt_applied_filter_lists + + def cim_applied_filter_lists(self, dom_name): + pass + # cim_applied_filter_lists # FilterListTest @@ -319,9 +335,17 @@ class FilterRule(object): __versions = {"ip" : "4", "ipv6": "6",} - __actions = {"accept" : "1", - "deny" : "2", - "drop" : "2",} + __actions = {"accept" : "1", + "deny" : "2", + "drop" : "2", + "reject" : "3", + "return" : "4", + "continue" : "5",} + + __protocolids = {"ipv4": "2048", + "arp" : "2054", + "rarp": "32821", + "ipv6": "34525",} __baserule_map = {"action" : "Action", "direction" : "Direction", @@ -394,7 +418,7 @@ class FilterRule(object): for e in element: self.__dict = dict(self.__dict, **e.attrib) - if not self.__type: + if self.__type is None: self.__type = e.tag try: @@ -415,6 +439,12 @@ class FilterRule(object): return self.__actions[self.__dict[key]] elif key == "type": return self.__type + elif key == "protocolid": + value = self.__dict[key] + try: + return self.__protocolids[value] + except KeyError: + return value try: return self.__dict[key] @@ -470,7 +500,7 @@ class FilterRule(object): # convert the property value to string prop = instance.properties[inst_key] val = self.__getattr__(key) - if val.startswith("0x"): + if isinstance(val, str) and val.startswith("0x"): inst_val = hex(int(prop.value)) else: inst_val = str(prop.value) -- 1.7.7.6 From xiaxia347work at 163.com Tue Jan 31 13:17:27 2012 From: xiaxia347work at 163.com (xiaxia347work at 163.com) Date: Tue, 31 Jan 2012 21:17:27 +0800 Subject: [Libvirt-cim] [PATCH V6 0/7] vlan extention - readonly Message-ID: <1328015847-20342-1-git-send-email-xiaxia347work@163.com> From: Wenchao Xia These patches add readonly portion of host network. v6: code changes according to v5 comments, added CIM model code. Added DHCP property in CIM model and EthIface structure. Wenchao Xia (7): vlan extention - readonly function libarary vlan extention - CIM model helper vlan extention - CIM model Makefile change vlan extention - CIM model add VESS vlan extention - CIM model add VESSSD vlan extention - CIM model add EthernetPort vlan extention - CIM model add EASD Makefile.am | 14 +- libxkutil/Makefile.am | 12 +- libxkutil/misc_util.c | 48 ++ libxkutil/misc_util.h | 3 + libxkutil/network_model_helper.c | 473 ++++++++++++ libxkutil/network_model_helper.h | 101 +++ libxkutil/network_parsing.c | 762 ++++++++++++++++++++ libxkutil/network_parsing.h | 176 +++++ libxkutil/network_parsing_test.c | 70 ++ libxkutil/xmlgen.c | 4 +- libxkutil/xmlgen.h | 4 + schema/EthernetPort.mof | 4 + schema/EthernetPort.registration | 3 + schema/EthernetPortAllocationSettingData.mof | 22 + .../EthernetPortAllocationSettingData.registration | 3 + schema/VirtualEthernetSwitchSystem.mof | 10 + schema/VirtualEthernetSwitchSystem.registration | 3 + schema/VirtualEthernetSwitchSystemSettingData.mof | 31 + ...ualEthernetSwitchSystemSettingData.registration | 3 + src/Makefile.am | 23 +- src/Virt_EASD.c | 709 ++++++++++++++++++ src/Virt_EASD.h | 59 ++ src/Virt_EthernetPort.c | 561 ++++++++++++++ src/Virt_EthernetPort.h | 58 ++ src/Virt_VESSSD.c | 382 ++++++++++ src/Virt_VESSSD.h | 39 + src/Virt_VirtualEthernetSwitchSystem.c | 478 ++++++++++++ src/Virt_VirtualEthernetSwitchSystem.h | 52 ++ 28 files changed, 4097 insertions(+), 10 deletions(-) create mode 100644 libxkutil/network_model_helper.c create mode 100644 libxkutil/network_model_helper.h create mode 100644 libxkutil/network_parsing.c create mode 100644 libxkutil/network_parsing.h create mode 100644 libxkutil/network_parsing_test.c create mode 100644 schema/EthernetPort.mof create mode 100644 schema/EthernetPort.registration create mode 100644 schema/EthernetPortAllocationSettingData.mof create mode 100644 schema/EthernetPortAllocationSettingData.registration create mode 100644 schema/VirtualEthernetSwitchSystem.mof create mode 100644 schema/VirtualEthernetSwitchSystem.registration create mode 100644 schema/VirtualEthernetSwitchSystemSettingData.mof create mode 100644 schema/VirtualEthernetSwitchSystemSettingData.registration create mode 100644 src/Virt_EASD.c create mode 100644 src/Virt_EASD.h create mode 100644 src/Virt_EthernetPort.c create mode 100644 src/Virt_EthernetPort.h create mode 100644 src/Virt_VESSSD.c create mode 100644 src/Virt_VESSSD.h create mode 100644 src/Virt_VirtualEthernetSwitchSystem.c create mode 100644 src/Virt_VirtualEthernetSwitchSystem.h From xiaxia347work at 163.com Tue Jan 31 13:18:30 2012 From: xiaxia347work at 163.com (xiaxia347work at 163.com) Date: Tue, 31 Jan 2012 21:18:30 +0800 Subject: [Libvirt-cim] [PATCH V6 1/7] vlan extention - readonly function libarary Message-ID: <1328015910-24242-1-git-send-email-xiaxia347work@163.com> From: Wenchao Xia This patch add function libarary and test program with libvirt API. Signed-off-by: Wenchao Xia --- libxkutil/Makefile.am | 12 +- libxkutil/misc_util.c | 48 +++ libxkutil/misc_util.h | 3 + libxkutil/network_parsing.c | 762 ++++++++++++++++++++++++++++++++++++++ libxkutil/network_parsing.h | 176 +++++++++ libxkutil/network_parsing_test.c | 70 ++++ libxkutil/xmlgen.c | 4 +- libxkutil/xmlgen.h | 4 + 8 files changed, 1074 insertions(+), 5 deletions(-) create mode 100644 libxkutil/network_parsing.c create mode 100644 libxkutil/network_parsing.h create mode 100644 libxkutil/network_parsing_test.c diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am index f1adc03..a1fc0b3 100644 --- a/libxkutil/Makefile.am +++ b/libxkutil/Makefile.am @@ -4,12 +4,14 @@ AM_CFLAGS = $(CFLAGS_STRICT) \ -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ - pool_parsing.h acl_parsing.h + pool_parsing.h acl_parsing.h \ + network_parsing.h network_model_helper.h lib_LTLIBRARIES = libxkutil.la libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ - xmlgen.c infostore.c pool_parsing.c acl_parsing.c + xmlgen.c infostore.c pool_parsing.c acl_parsing.c \ + network_parsing.c network_model_helper.c libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ @LIBUUID_LIBS@ @@ -19,3 +21,9 @@ noinst_PROGRAMS = xml_parse_test xml_parse_test_SOURCES = xml_parse_test.c xml_parse_test_LDADD = libxkutil.la \ @LIBVIRT_LIBS@ + +noinst_PROGRAMS += network_parsing_test + +network_parsing_test_SOURCES = network_parsing_test.c +network_parsing_test_LDADD = libxkutil.la \ + @LIBVIRT_LIBS@ diff --git a/libxkutil/misc_util.c b/libxkutil/misc_util.c index 61893c3..564c6f2 100644 --- a/libxkutil/misc_util.c +++ b/libxkutil/misc_util.c @@ -184,6 +184,54 @@ virConnectPtr connect_by_classname(const CMPIBroker *broker, return conn; } +virConnectPtr connect_any(void) +{ + const char *uri = NULL; + virConnectPtr conn = NULL; + hypervisor_status_t *h = NULL; + const char *classname = NULL; + + for (h = &hypervisor_list[0]; h != NULL; h++) { + if (h->enabled) { + + classname = h->name; + + uri = cn_to_uri(classname); + if (!uri) { + CU_DEBUG("Unable to gen URI from classname," + " uri is %s.", uri); + return NULL; + } + CU_DEBUG("Connecting to libvirt with uri `%s'", uri); + + pthread_mutex_lock(&libvirt_mutex); + + if (is_read_only()) + conn = virConnectOpenReadOnly(uri); + else + conn = virConnectOpen(uri); + + pthread_mutex_unlock(&libvirt_mutex); + + if (!conn) { + virErrorPtr error = virGetLastError(); + if (error->code == VIR_ERR_NO_CONNECT) + set_hypervisor_disabled(classname); + + CU_DEBUG("Unable to connect to `%s'", uri); + continue; + } else { + break; + } + } + } + + if (classname == NULL) { + CU_DEBUG("Failed to find any hypervisor."); + } + return conn; +} + void free_domain_list(virDomainPtr *list, int count) { int i; diff --git a/libxkutil/misc_util.h b/libxkutil/misc_util.h index c7a2122..d1cc081 100644 --- a/libxkutil/misc_util.h +++ b/libxkutil/misc_util.h @@ -57,6 +57,9 @@ virConnectPtr connect_by_classname(const CMPIBroker *broker, const char *classname, CMPIStatus *s); +/* Try connect to any hypervisor available */ +virConnectPtr connect_any(void); + /* Establish a libvirt connection to the appropriate hypervisor, * as determined by the state of the system, or the value of the * HYPURI environment variable, if set. diff --git a/libxkutil/network_parsing.c b/libxkutil/network_parsing.c new file mode 100644 index 0000000..aa1b2e7 --- /dev/null +++ b/libxkutil/network_parsing.c @@ -0,0 +1,762 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "misc_util.h" +#include "xmlgen.h" +#include "device_parsing.h" +#include "network_parsing.h" + +#define LIST_INACTIVE_IFACE 1 +#define LIST_ACTIVE_IFACE 2 + +static void vlan_prop_print(struct VLAN_Prop *pvlan_prop) +{ + struct VLAN_Prop_8021q *p_8021q; + CU_DEBUG_OP(1, "--VLAN props: type %d.\n", + pvlan_prop->vlan_type); + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + CU_DEBUG_OP(1, "----IEEE802.1.Q: id %d, parent %s.\n", + p_8021q->vlan_id, p_8021q->parent); + } +} + +static void br_prop_print(struct BR_Prop *pbr_prop) +{ + int i = 0; + CU_DEBUG_OP(1, "--Bridge props: stp %d, delay %d, port_num %d.\n", + pbr_prop->STP, pbr_prop->delay, pbr_prop->port_num); + if (pbr_prop->port_names != NULL) { + CU_DEBUG_OP(1, "----Ports attached: "); + while (i < pbr_prop->port_num) { + CU_DEBUG_OP(1, " %s,", *(pbr_prop->port_names+i)); + i++; + } + CU_DEBUG_OP(1, "\n"); + } +} + +void eth_iface_print(struct EthIface *piface) +{ + CU_DEBUG_OP(1, "Iface device: name %s.\n" + "--Main Props: parent %s, attach to %s, mac %s, iface type %d," + " status %d, boot_mode %d," + " protocol ipv4 dhcp %d.\n", + piface->name, + piface->dep_ifname, piface->attach_bridge, piface->mac, piface->eth_type, + piface->run_prop.status, piface->run_prop.boot_mode, + piface->protocol_prop.ipv4_prop.DHCP); + if (piface->pbr_prop != NULL) { + br_prop_print(piface->pbr_prop); + } + if (piface->pvlan_prop != NULL) { + vlan_prop_print(piface->pvlan_prop); + } + return; +} + +void eth_ifaceslist_print(struct EthIfacesList *plist) +{ + int i = 0; + CU_DEBUG_OP(1, "Have %d ifaces in the list:\n", plist->count); + while (i < plist->count) { + CU_DEBUG_OP(1, "%04d ", i); + eth_iface_print(plist->pifaces[i]); + i++; + } +} + +static void vlan_prop_init(struct VLAN_Prop *pvlan_prop, int vlan_type) +{ + struct VLAN_Prop_8021q *p_8021q; + memset(pvlan_prop, 0, sizeof(struct VLAN_Prop)); + pvlan_prop->vlan_type = vlan_type; + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + p_8021q->vlan_id = NUM_NONE; + } +} + +static void br_prop_init(struct BR_Prop *pbr_prop) +{ + memset(pbr_prop, 0, sizeof(struct BR_Prop)); + pbr_prop->STP = NUM_NONE; + pbr_prop->delay = NUM_NONE; + pbr_prop->port_num = NUM_NONE; +} + +void eth_iface_init(struct EthIface *piface) +{ + memset(piface, 0, sizeof(struct EthIface)); + piface->eth_type = ETH_TYPE_NOT_GOT; + piface->run_prop.status = NUM_NONE; + piface->run_prop.boot_mode = BOOT_MODE_NOT_GOT; + piface->protocol_prop.ipv4_prop.DHCP = NUM_NONE; + return; +} + +void eth_iface_add_br_prop(struct EthIface *piface) +{ + if (piface->pbr_prop != NULL) { + return; + } + CU_MALLOC(piface->pbr_prop, sizeof(struct BR_Prop)); + br_prop_init(piface->pbr_prop); +} + +void eth_iface_add_vlan_prop(struct EthIface *piface, int vlan_type) +{ + if (piface->pvlan_prop != NULL) { + return; + } + CU_MALLOC(piface->pvlan_prop, sizeof(struct VLAN_Prop)); + vlan_prop_init(piface->pvlan_prop, vlan_type); +} + +static void vlan_prop_uninit(struct VLAN_Prop *pvlan_prop) +{ + struct VLAN_Prop_8021q *p_8021q; + if (pvlan_prop == NULL) { + return; + } + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + CU_FREE(p_8021q->parent); + } +} + +static void br_prop_uninit(struct BR_Prop *pbr_prop) +{ + int i = 0; + if (pbr_prop == NULL) { + return; + } + if (pbr_prop->port_names != NULL) { + while (i < pbr_prop->port_num) { + CU_FREE(pbr_prop->port_names[i]); + i++; + } + CU_FREE(pbr_prop->port_names); + } +} + +void eth_iface_uninit(struct EthIface *piface) +{ + if (piface == NULL) { + return; + } + CU_FREE(piface->name); + CU_FREE(piface->dep_ifname); + CU_FREE(piface->attach_bridge); + CU_FREE(piface->mac); + br_prop_uninit(piface->pbr_prop); + CU_FREE(piface->pbr_prop); + vlan_prop_uninit(piface->pvlan_prop); + CU_FREE(piface->pvlan_prop); + return; +} + +void eth_ifaceslist_init(struct EthIfacesList *plist) +{ + plist->count = 0; +} + +void eth_ifaceslist_uninit(struct EthIfacesList *plist) +{ + struct EthIface **t = NULL; + int i = 0; + if (plist->count <= 0) { + return; + } + t = plist->pifaces; + while (i < plist->count) { + if (*t != NULL) { + eth_iface_uninit(*t); + CU_FREE(*t); + } + t++; + i++; + } + return; +} + +int eth_ifaceslist_add(struct EthIfacesList *plist, struct EthIface **ppiface) +{ + if (plist->count >= MAX_IFACE_NUM) { + CU_DEBUG("Too much device found."); + return 0; + } + plist->pifaces[plist->count] = *ppiface; + *ppiface = NULL; + plist->count++; + return 1; +} + +struct EthIface *eth_ifaceslist_search(struct EthIfacesList *plist, + char *name) +{ + int i = 0; + struct EthIface *piface = NULL; + + while (i < plist->count) { + piface = plist->pifaces[i]; + i++; + if (piface != NULL) { + if (strcmp(piface->name, name) == 0) { + return piface; + } + } + } + return NULL; +} + +/* the judgement condition is weak, but I can't find a better way */ +int eth_iface_filter_peths(const struct EthIface *piface, void *nouse) +{ + if ((piface->eth_type != ETH_TYPE_ETHER_ANY) && + (piface->eth_type != ETH_TYPE_ETHER_PHYSICAL)) { + return 0; + } + if (piface->dep_ifname != NULL) { + return 0; + } + if (NULL != strstr(piface->name, ".")) { + return 0; + } + /* this filter NetUSB etc */ + if (NULL == strstr(piface->name, "eth")) { + return 0; + } + + return 1; +} + +char *get_host_iface_error_reason(int errno) +{ + char *ret = NULL; + switch (errno) { + case ERR_CONNECT: + ret = "Error in connect to hypervisor."; + break; + + case ERR_LIST_INTERFACE: + ret = "Error in listing the interfaces."; + break; + + default: + ret = "Internal error in calling libvirt API for interfaces."; + break; + } + return ret; +} + +/* Dummy function to suppress error message from libxml2 */ +static void swallow_err_msg(void *ctx, const char *msg, ...) +{ + /* do nothing, just swallow the message. */ +} + + +static const char *gen_eth_xmlnode_iface(xmlNodePtr root, + struct EthIface *piface, + struct EthIfacesList *plist, + int bridge_port_flag) +{ + const char *msg = NULL; + xmlNodePtr temp_node1 = NULL, temp_node2 = NULL, temp_node3 = NULL; + char *str = NULL, buf[16] = {0,}; + int i = 0; + struct EthIface *pifaceport; + + if (piface->name == NULL) { + msg = "Iface have no name.\n"; + goto out; + } + /* netcfg have no xml for iface attatched to bridge */ + if ((piface->attach_bridge != NULL) && (bridge_port_flag != 1)) { + goto out; + } + + temp_node1 = xmlNewChild(root, NULL, BAD_CAST "interface", NULL); + if (temp_node1 == NULL) { + msg = XML_ERROR; + goto out; + } + xmlNewProp(temp_node1, BAD_CAST "name", BAD_CAST piface->name); + + if (piface->eth_type == ETH_TYPE_ETHER_BRIDGE) { + str = "bridge"; + } else if (piface->eth_type == ETH_TYPE_ETHER_VLAN) { + str = "vlan"; + } else { + str = "ethernet"; + } + xmlNewProp(temp_node1, BAD_CAST "type", BAD_CAST str); + + if ((piface->pvlan_prop != NULL) && + (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q)) { + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "vlan", NULL); + snprintf(buf, sizeof(buf), + "%d", piface->pvlan_prop->props.prop_8021q.vlan_id); + xmlNewProp(temp_node2, BAD_CAST "tag", BAD_CAST buf); + temp_node3 = xmlNewChild(temp_node2, NULL, BAD_CAST "interface", NULL); + xmlNewProp(temp_node3, BAD_CAST "name", + BAD_CAST piface->pvlan_prop->props.prop_8021q.parent); + } + + /* if it is attached to bridge, only above properties could be set */ + if (bridge_port_flag == 1) { + goto out; + } + + if (piface->protocol_prop.ipv4_prop.DHCP == 1) { + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "protocol", NULL); + xmlNewProp(temp_node2, BAD_CAST "family", BAD_CAST "ipv4"); + temp_node3 = xmlNewChild(temp_node2, NULL, BAD_CAST "dhcp", NULL); + } + + if (piface->pbr_prop != NULL) { + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "bridge", NULL); + if (piface->pbr_prop->STP == 1) { + snprintf(buf, sizeof(buf), "on"); + } else { + snprintf(buf, sizeof(buf), "off"); + } + xmlNewProp(temp_node2, BAD_CAST "stp", BAD_CAST buf); + if (piface->pbr_prop->delay >= 0) { + snprintf(buf, sizeof(buf), "%d", piface->pbr_prop->delay); + xmlNewProp(temp_node2, BAD_CAST "delay", BAD_CAST buf); + } + if ((piface->pbr_prop->port_names != NULL) && + (piface->pbr_prop->port_num > 0)) { + for (i = 0; i < piface->pbr_prop->port_num; i++) { + pifaceport = eth_ifaceslist_search(plist, + piface->pbr_prop->port_names[i]); + if (pifaceport == NULL) { + CU_DEBUG("failed to find port %s of bridge %s in list.", + piface->pbr_prop->port_names[i], piface->name); + } else { + gen_eth_xmlnode_iface(temp_node2, pifaceport, plist, 1); + } + } + } + } + + if (piface->run_prop.boot_mode == BOOT_MODE_AUTOSTART) { + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "start", NULL); + xmlNewProp(temp_node2, BAD_CAST "mode", BAD_CAST "onboot"); + } else if (piface->run_prop.boot_mode == BOOT_MODE_NONE) { + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "start", NULL); + xmlNewProp(temp_node2, BAD_CAST "mode", BAD_CAST "none"); + } + if (piface->mac != NULL) { + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "mac", NULL); + xmlNewProp(temp_node2, BAD_CAST "address", BAD_CAST piface->mac); + } + + out: + return msg; +} + +static const char *gen_eth_xmlnode(xmlNodePtr root, + struct EthIfacesList *plist) +{ + const char *msg = NULL; + int i = 0; + struct EthIface *piface = NULL; + + while (i < plist->count) { + piface = plist->pifaces[i]; + i++; + msg = gen_eth_xmlnode_iface(root, piface, plist, 0); + if (msg != NULL) { + goto out; + } + } + + out: + return msg; +} + +const char *EthIfaceListTOXML(char **ppxml, + struct EthIfacesList *plist, + int dump_all_flag) +{ + const char *msg = NULL; + xmlNodePtr root = NULL; + + root = xmlNewNode(NULL, BAD_CAST "tmp"); + if (root == NULL) { + msg = "Failed to create root node."; + goto out; + } + msg = gen_eth_xmlnode(root, plist); + if (msg == NULL) { + if (dump_all_flag == 1) { + *ppxml = tree_to_xml(root); + } else { + *ppxml = tree_to_xml(root->children); + } + } + + out: + xmlFreeNode(root); + return msg; +} + +static int host_iface_adjust(struct EthIface *piface) +{ + if (1 == eth_iface_filter_peths(piface, NULL)) { + piface->eth_type = ETH_TYPE_ETHER_PHYSICAL; + } + return 1; +} + +static int parse_eth_xmlnode(struct EthIfacesList *plist, xmlNode *inode, + int status, char *attached, + eth_iface_filter_func filter_func, + void *filter_opaque) +{ + struct EthIface *piface = NULL; + xmlNode *child1 = NULL, *child2 = NULL; + char *temp = NULL, **ppchar; + int filter_ret = 0; + + CU_MALLOC(piface, sizeof(struct EthIface)); + eth_iface_init(piface); + + piface->name = get_attr_value(inode, "name"); + piface->run_prop.status = status; + if (attached != NULL) { + piface->attach_bridge = strdup(attached); + } + temp = get_attr_value(inode, "type"); + if (temp != NULL) { + if (strcmp(temp, "ethernet") == 0) { + piface->eth_type = ETH_TYPE_ETHER_ANY; + } + if (strcmp(temp, "bridge") == 0) { + piface->eth_type = ETH_TYPE_ETHER_BRIDGE; + } + if (strcmp(temp, "vlan") == 0) { + piface->eth_type = ETH_TYPE_ETHER_VLAN; + } + CU_FREE(temp); + } + + for (child1 = inode->children; child1 != NULL; child1 = child1->next) { + if (XSTREQ(child1->name, "start")) { + temp = get_attr_value(child1, "mode"); + if (strcmp(temp, "onboot") == 0) { + piface->run_prop.boot_mode = BOOT_MODE_AUTOSTART; + } + if (strcmp(temp, "none") == 0) { + piface->run_prop.boot_mode = BOOT_MODE_NONE; + } + CU_FREE(temp); + } + if (XSTREQ(child1->name, "mac")) { + piface->mac = get_attr_value(child1, "address"); + } + if (XSTREQ(child1->name, "protocol")) { + temp = get_attr_value(child1, "family"); + if (strcmp(temp, "ipv4") == 0) { + for (child2 = child1->children; child2 != NULL; + child2 = child2->next) { + if (XSTREQ(child2->name, "dhcp")) { + piface->protocol_prop.ipv4_prop.DHCP = 1; + break; + } + } + } + CU_FREE(temp); + } + if (XSTREQ(child1->name, "bridge")) { + eth_iface_add_br_prop(piface); + temp = get_attr_value(child1, "stp"); + if (strcmp(temp, "on") == 0) { + piface->pbr_prop->STP = 1; + } + if (strcmp(temp, "off") == 0) { + piface->pbr_prop->STP = 0; + } + CU_FREE(temp); + temp = get_attr_value(child1, "delay"); + piface->pbr_prop->delay = strtol(temp, NULL, 10); + CU_FREE(temp); + } + if (XSTREQ(child1->name, "bridge")) { + eth_iface_add_br_prop(piface); + temp = get_attr_value(child1, "stp"); + if (strcmp(temp, "on") == 0) { + piface->pbr_prop->STP = 1; + } + if (strcmp(temp, "off") == 0) { + piface->pbr_prop->STP = 0; + } + CU_FREE(temp); + temp = get_attr_value(child1, "delay"); + piface->pbr_prop->delay = strtol(temp, NULL, 10); + CU_FREE(temp); + for (child2 = child1->children; child2 != NULL; + child2 = child2->next) { + if (XSTREQ(child2->name, "interface")) { + if (piface->pbr_prop->port_names == NULL) { + CU_CALLOC(piface->pbr_prop->port_names, + MAX_IFACE_NUM, sizeof(char *)); + piface->pbr_prop->port_num = 0; + } + ppchar = piface->pbr_prop->port_names + + (piface->pbr_prop->port_num)++; + *ppchar = get_attr_value(child2, "name"); + parse_eth_xmlnode(plist, child2, status, piface->name, + filter_func, filter_opaque); + } + } + } + if (XSTREQ(child1->name, "vlan")) { + eth_iface_add_vlan_prop(piface, VLAN_TYPE_802_1_Q); + temp = get_attr_value(child1, "tag"); + piface->pvlan_prop->props.prop_8021q.vlan_id = + strtol(temp, NULL, 10); + CU_FREE(temp); + for (child2 = child1->children; child2 != NULL; + child2 = child2->next) { + if (XSTREQ(child2->name, "interface")) { + piface->pvlan_prop->props.prop_8021q.parent = + get_attr_value(child2, "name"); + piface->dep_ifname = + get_attr_value(child2, "name"); + } + } + } + } + + host_iface_adjust(piface); + + filter_ret = 1; + if (filter_func != NULL) { + filter_ret = filter_func(piface, filter_opaque); + } + if (filter_ret == 1) { + eth_ifaceslist_add(plist, &piface); + } + return 1; +} + +static const char *XMLToEthIfaceList(struct EthIfacesList *plist, + const char *xml, + int status, + eth_iface_filter_func filter_func, + void *filter_opaque) +{ + xmlDoc *xmldoc = NULL; + xmlXPathContext *xpathCtx = NULL; + xmlXPathObject *xpathObj = NULL; + xmlChar *xpathstr = NULL; + xmlNode **dev_nodes = NULL; + xmlNodeSet *nsv = NULL; + int count = 0; + int len = 0, devidx = 0; + const char *msg = NULL; + + len = strlen(xml) + 1; + xpathstr = (xmlChar *)"/interface"; + + xmlSetGenericErrorFunc(NULL, swallow_err_msg); + if ((xmldoc = xmlParseMemory(xml, len)) == NULL) { + msg = "Failed to get xmldoc."; + goto err1; + } + + if ((xpathCtx = xmlXPathNewContext(xmldoc)) == NULL) { + msg = "Failed to get pathCtx"; + goto err2; + } + + if ((xpathObj = xmlXPathEvalExpression(xpathstr, xpathCtx)) + == NULL) { + msg = "Failed to get xpathObj"; + goto err3; + } + + nsv = xpathObj->nodesetval; + if (nsv == NULL) { + msg = "Failed to get nodesetval."; + goto out; + } + + dev_nodes = nsv->nodeTab; + count = nsv->nodeNr; + + if (count <= 0) { + msg = "Nodesetval have less that 1 values."; + goto out; + } + + for (devidx = 0; devidx < count; devidx++) { + parse_eth_xmlnode(plist, dev_nodes[devidx], status, NULL, + filter_func, filter_opaque); + } + + out: + xmlSetGenericErrorFunc(NULL, NULL); + xmlXPathFreeObject(xpathObj); + + err3: + xmlXPathFreeContext(xpathCtx); + err2: + xmlFreeDoc(xmldoc); + err1: + return msg; +} + +int get_host_ifaces(struct EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque) +{ + virConnectPtr conn = NULL; + virInterfacePtr iface = NULL; + int ret = 0; + int num = 0, listnum = 0, i = 0; + char **names = NULL; + char *xml = NULL; + int flags = 0; + const char *msg = NULL; + int list_flag = LIST_INACTIVE_IFACE | LIST_ACTIVE_IFACE; + int xml_flag = VIR_INTERFACE_XML_INACTIVE; + //CMPIStatus s; + + //conn = connect_by_classname(NULL, "xen", &s); + conn = connect_any(); + if (conn == NULL) { + CU_DEBUG("Connect for network failed."); + ret = ERR_CONNECT; + goto out; + } + + /* list defined interfaces*/ + if ((list_flag & LIST_INACTIVE_IFACE) == 0) { + goto list_active; + } + num = virConnectNumOfDefinedInterfaces(conn); + if (num < 0) { + CU_DEBUG("Failed to find number of defined interfaces."); + ret = ERR_LIST_INTERFACE; + goto out; + } + names = malloc(num * sizeof(char *)); + listnum = virConnectListDefinedInterfaces(conn, names, num); + if (listnum < 0) { + CU_DEBUG("Failed to list names of defined interfaces."); + ret = ERR_LIST_INTERFACE; + goto out; + } + CU_DEBUG("%d defined ifaces found from libvirt API.\n", listnum); + + flags = xml_flag; + for (i = 0; i < listnum; i++) { + iface = virInterfaceLookupByName(conn, names[i]); + if (!iface) { + CU_DEBUG("Failed to look up %s.\n", names[i]); + CU_FREE(names[i]); + continue; + } + CU_FREE(names[i]); + xml = virInterfaceGetXMLDesc(iface, flags); + CU_DEBUG("Defined interface %d xml:\n%s", i, xml); + msg = XMLToEthIfaceList(plist, xml, ETH_STATE_INACTIVE, + filter_func, filter_opaque); + if (msg != NULL) { + CU_DEBUG("Failed parsing eth xml, msg is: %s.", msg); + } + CU_FREE(xml); + virInterfaceFree(iface); + } + CU_FREE(names); + + list_active: + /* list active interfaces*/ + if ((list_flag & LIST_ACTIVE_IFACE) == 0) { + goto out; + } + num = virConnectNumOfInterfaces(conn); + if (num < 0) { + CU_DEBUG("Failed to find number of active interfaces."); + ret = ERR_LIST_INTERFACE; + goto out; + } + names = malloc(num * sizeof(char *)); + + listnum = virConnectListInterfaces(conn, names, num); + if (listnum < 0) { + CU_DEBUG("Failed to list names of active interfacess."); + ret = ERR_LIST_INTERFACE; + goto out; + } + CU_DEBUG("%d active ifaces found from libvirt API.\n", listnum); + + flags = xml_flag; + for (i = 0; i < listnum; i++) { + iface = virInterfaceLookupByName(conn, names[i]); + if (!iface) { + CU_DEBUG("Failed to look up %s.\n", names[i]); + CU_FREE(names[i]); + continue; + } + CU_FREE(names[i]); + xml = virInterfaceGetXMLDesc(iface, flags); + CU_DEBUG("Active interface %d xml:\n%s", i, xml); + msg = XMLToEthIfaceList(plist, xml, ETH_STATE_ACTIVE, + filter_func, filter_opaque); + if (msg != NULL) { + CU_DEBUG("Failed parsing eth xml, msg is: %s.", msg); + } + CU_FREE(xml); + virInterfaceFree(iface); + } + ret = 1; + + out: + virConnectClose(conn); + CU_FREE(names); + return ret; +} +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/libxkutil/network_parsing.h b/libxkutil/network_parsing.h new file mode 100644 index 0000000..5994f78 --- /dev/null +++ b/libxkutil/network_parsing.h @@ -0,0 +1,176 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#ifndef NETWORK_PARSING_H +#define NETWORK_PARSING_H + +#include +#include +#include + +/* value defines */ +#define MAX_IFACE_NUM 4096 + +#define NUM_NONE -1 + +#define CU_DEBUG_LEVEL 2 + +/* macro functions */ +#define CU_DEBUG_OP(lvl, fmt, args...) do { \ + if (CU_DEBUG_LEVEL && (lvl) <= CU_DEBUG_LEVEL) { \ + debug_print(fmt, ##args); \ + } \ +} while (0) + +#define CU_MALLOC(p, size) \ +{ \ + (p) = malloc((size)); \ + if ((p) == NULL) { \ + CU_DEBUG("malloc failed."); \ + } \ +} + +#define CU_CALLOC(p, nmen, size) \ +{ \ + (p) = calloc((nmen), (size)); \ + if ((p) == NULL) { \ + CU_DEBUG("calloc failed."); \ + } \ +} + +#define CU_FREE(p) {free(p); (p) = NULL; } + +#define CU_STRDUP(p) (p) == NULL ? NULL : strdup(p); + +#define ERR_CONNECT -1 +#define ERR_LIST_INTERFACE -2 + +typedef enum { + ETH_TYPE_NOT_GOT = NUM_NONE, + ETH_TYPE_ETHER_ANY = 0x0001, + ETH_TYPE_ETHER_PHYSICAL = 0x0002, + ETH_TYPE_ETHER_BRIDGE = 0x0004, + ETH_TYPE_ETHER_VLAN = 0x0008 +} EthType; + +typedef enum { + VLAN_TYPE_NOT_GOT = NUM_NONE, + VLAN_TYPE_802_1_Q = 1, + VLAN_TYPE_802_1_QBG = 2, + VLAN_TYPE_802_1_QBH = 4 +} VLANType; + +typedef enum { + BOOT_MODE_NOT_GOT = NUM_NONE, + BOOT_MODE_NONE = 0, + BOOT_MODE_AUTOSTART = 1 +} BootMode; + +typedef enum { + ETH_STATE_INACTIVE = 0, + ETH_STATE_ACTIVE = 1 +} Status; + +struct IPV4_Prop { + int DHCP; +} ; + +struct Protocol_Prop { + struct IPV4_Prop ipv4_prop; +} ; + +struct BR_Prop { + int STP; + int delay; + char **port_names; + int port_num; +} ; + +struct Run_Prop { + Status status; + BootMode boot_mode; +} ; + +struct VLAN_Prop_8021q { + int vlan_id; + char *parent; +} ; + +/* HP vlan standard, TBD */ +struct VLAN_Prop_8021qbg { + int invalid; +} ; + +/* Cisco and VMware vlan standard, TBD */ +struct VLAN_Prop_8021qbh { + int invalid; +} ; + +struct VLAN_Prop { + int vlan_type; + union { + struct VLAN_Prop_8021q prop_8021q; + struct VLAN_Prop_8021qbg prop_8021qbg; + struct VLAN_Prop_8021qbh prop_8021qbh; + } props; +} ; + +/* EthIface is logical devices include eth ports and bridges */ +struct EthIface { + char *name; + char *dep_ifname; /* parent dev name */ + char *attach_bridge; /* bridge the iface is attached to */ + char *mac; + EthType eth_type; + struct Run_Prop run_prop; + struct Protocol_Prop protocol_prop; + /* optional properties */ + struct BR_Prop *pbr_prop; + struct VLAN_Prop *pvlan_prop; +} ; + +struct EthIfacesList { + struct EthIface *pifaces[MAX_IFACE_NUM]; + int count; +} ; + +void eth_iface_init(struct EthIface *piface); +void eth_iface_add_br_prop(struct EthIface *piface); +void eth_iface_add_vlan_prop(struct EthIface *piface, int vlan_type); +void eth_iface_uninit(struct EthIface *piface); + +void eth_ifaceslist_init(struct EthIfacesList *plist); +void eth_ifaceslist_uninit(struct EthIfacesList *plist); +/* ppiface must be allocated from heap, to save code of struct duplication */ +int eth_ifaceslist_add(struct EthIfacesList *plist, struct EthIface **ppiface); +/* returned pointer is direct reference to a member in plist */ +struct EthIface *eth_ifaceslist_search(struct EthIfacesList *plist, + char *name); + +void eth_iface_print(struct EthIface *piface); +void eth_ifaceslist_print(struct EthIfacesList *plist); + +typedef int (*eth_iface_filter_func)(const struct EthIface *piface, + void *opaque); + +int eth_iface_filter_peths(const struct EthIface *piface, void *nouse); + +int get_host_ifaces(struct EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque); + +char *get_host_iface_error_reason(int errno); + +const char *EthIfaceListTOXML(char **ppxml, + struct EthIfacesList *plist, + int dump_all_flag); + +#endif diff --git a/libxkutil/network_parsing_test.c b/libxkutil/network_parsing_test.c new file mode 100644 index 0000000..31a1a3b --- /dev/null +++ b/libxkutil/network_parsing_test.c @@ -0,0 +1,70 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "misc_util.h" +#include "device_parsing.h" +#include "network_parsing.h" + +static long print_and_ret_time_stamp(void) +{ + struct timeval tv; + long ret; + gettimeofday(&tv, NULL); + ret = tv.tv_sec*1000 + tv.tv_usec/1000; + CU_DEBUG("time is [%ld] ms.", ret); + return ret; +} + +/* try retrieve all information, and then map them back to xml. */ +int main(int argc, char **argv) +{ + libvirt_cim_init(); + struct EthIfacesList *plist = NULL; + const char *msg = NULL; + char *genxml = NULL; + long start_time, end_time; + + CU_MALLOC(plist, sizeof(struct EthIfacesList)); + eth_ifaceslist_init(plist); + + start_time = print_and_ret_time_stamp(); + get_host_ifaces(plist, NULL, NULL); + end_time = print_and_ret_time_stamp(); + CU_DEBUG("cost [%d]ms in discovering host network. Result:", + end_time - start_time); + eth_ifaceslist_print(plist); + + msg = EthIfaceListTOXML(&genxml, plist, 1); + CU_DEBUG("xml gen msg is %s. xml is:\n%s", msg, genxml); + CU_FREE(genxml); + + eth_ifaceslist_uninit(plist); + CU_FREE(plist); + return 0; +} diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index 9a2ada9..33da52b 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -35,8 +35,6 @@ #include "cmpimacs.h" #endif -#define XML_ERROR "Failed to allocate XML memory" - typedef const char *(*devfn_t)(xmlNodePtr node, struct domain *dominfo); typedef const char *(*poolfn_t)(xmlNodePtr node, struct virt_pool *pool); typedef const char *(*resfn_t)(xmlNodePtr node, struct virt_pool_res *res); @@ -830,7 +828,7 @@ static char *features_xml(xmlNodePtr root, struct domain *domain) return NULL; } -static char *tree_to_xml(xmlNodePtr root) +char *tree_to_xml(xmlNodePtr root) { xmlBufferPtr buffer = NULL; xmlSaveCtxtPtr savectx = NULL; diff --git a/libxkutil/xmlgen.h b/libxkutil/xmlgen.h index 743fc82..9c88986 100644 --- a/libxkutil/xmlgen.h +++ b/libxkutil/xmlgen.h @@ -27,11 +27,15 @@ #include "cmpidt.h" +#define XML_ERROR "Failed to allocate XML memory" + struct kv { const char *key; const char *val; }; +char *tree_to_xml(xmlNodePtr root); + char *system_to_xml(struct domain *dominfo); char *device_to_xml(struct virt_device *dev); -- 1.7.1 From xiaxia347work at 163.com Tue Jan 31 13:19:14 2012 From: xiaxia347work at 163.com (xiaxia347work at 163.com) Date: Tue, 31 Jan 2012 21:19:14 +0800 Subject: [Libvirt-cim] [PATCH V6 2/7] vlan extention - CIM model helper Message-ID: <1328015954-27753-1-git-send-email-xiaxia347work@163.com> From: Wenchao Xia This patch add helper functions for building up CIM network model. Signed-off-by: Wenchao Xia --- libxkutil/network_model_helper.c | 473 ++++++++++++++++++++++++++++++++++++++ libxkutil/network_model_helper.h | 101 ++++++++ 2 files changed, 574 insertions(+), 0 deletions(-) create mode 100644 libxkutil/network_model_helper.c create mode 100644 libxkutil/network_model_helper.h diff --git a/libxkutil/network_model_helper.c b/libxkutil/network_model_helper.c new file mode 100644 index 0000000..9bb3e83 --- /dev/null +++ b/libxkutil/network_model_helper.c @@ -0,0 +1,473 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "network_model_helper.h" +#include "device_parsing.h" + +#include "cmpidt.h" +#include "cmpift.h" +#include "cmpimacs.h" + +/* this function would return a new allocated string or NULL */ +char *compare_and_switch_prefix(const char *orig_str, + const char *orig_prefix, + const char *dest_prefix) +{ + int orig_prefix_len, dest_prefix_len, asret; + char *retstr = NULL; + const char *suffix; + if (orig_str == NULL) { + goto out; + } + orig_prefix_len = strlen(orig_prefix); + dest_prefix_len = strlen(dest_prefix); + if (0 != strncmp(orig_str, orig_prefix, orig_prefix_len)) { + goto out; + } + suffix = orig_str + orig_prefix_len; + asret = asprintf(&retstr, "%s%s", dest_prefix, suffix); + if (asret == -1) { + free(retstr); + retstr = NULL; + } + out: + return retstr; +} + +char *switch_device_id_prefix(const char *whole_id, + const char *orig_prefix, + const char *dest_prefix) +{ + char *system = NULL; + char *device = NULL; + char *new_id = NULL; + char *retstr = NULL; + int asret; + + + if (0 == parse_fq_devid(whole_id, &system, &device)) { + goto out; + } + + new_id = compare_and_switch_prefix(device, + orig_prefix, dest_prefix); + + if (new_id == NULL) { + goto out; + } + asret = asprintf(&retstr, "%s/%s", system, new_id); + if (asret == -1) { + free(retstr); + retstr = NULL; + } + + out: + free(system); + free(device); + free(new_id); + return retstr; +} + +char *ep_id_to_easdea_id(const char *epid) +{ + return switch_device_id_prefix(epid, + ETHPORT_PREFIX, ETHPORT_ALLOCATION_SD_PREFIX); +} + +char *easdea_id_to_ep_id(const char *epid) +{ + return switch_device_id_prefix(epid, + ETHPORT_ALLOCATION_SD_PREFIX, ETHPORT_PREFIX); +} + +char *ep_id_to_easdec_id(const char *epid) +{ + return switch_device_id_prefix(epid, + ETHPORT_PREFIX, ETHPORT_CONNECTION_SD_PREFIX); +} + +char *easdec_id_to_ep_id(const char *epid) +{ + return switch_device_id_prefix(epid, + ETHPORT_CONNECTION_SD_PREFIX, ETHPORT_PREFIX); +} + +char *vlanid_to_connection_name(const int id) +{ + int asret; + char *str = NULL; + char *prefix = CONNECTION_VLAN_PREFIX; + asret = asprintf(&str, "%s%d", prefix, id); + if (asret == -1) { + return NULL; + } + return str; +} + +int vlanid_from_connection_name(const char *name) +{ + int id = -1; + int temp = -1; + char *prefix = CONNECTION_VLAN_PREFIX; + char *dig_start, *dig_end; + if (name == NULL) { + goto out; + } + dig_start = strstr(name, prefix); + if (dig_start == NULL) { + goto out; + } + dig_start += strlen(prefix); + temp = strtol(dig_start, &dig_end, 10); + if ((dig_start == dig_end) || (temp < 0) || (temp > 4095)) { + goto out; + } + id = temp; + out: + return id; +} + +int eth_iface_filter_cim_ethport(const struct EthIface *piface, + void *nouse) +{ + if ((piface->eth_type != ETH_TYPE_NOT_GOT) && + (piface->eth_type != ETH_TYPE_ETHER_BRIDGE)) { + return 1; + } + return 0; +} + +int eth_iface_filter_cim_ethport_for_name(const struct EthIface *piface, + void *name) +{ + int cim_ethport_flag; + cim_ethport_flag = eth_iface_filter_cim_ethport(piface, NULL); + if (cim_ethport_flag == 1) { + if (0 == strcmp(piface->name, name)) { + return 1; + } + } + return 0; +} + +/* returned value need to be freed */ +char *get_ethportsd_name_from_iface(const char *iface_name, const int type) +{ + char *prefix; + char *name; + int size; + + if (iface_name == NULL) { + return NULL; + } + + if (type == EASD_TYPE_EA) { + prefix = ETHPORT_ALLOCATION_SD_PREFIX; + } else { + prefix = ETHPORT_CONNECTION_SD_PREFIX; + } + + size = strlen(iface_name)+strlen(prefix)+1; + CU_MALLOC(name, size); + snprintf(name, size, "%s%s", prefix, iface_name); + return name; +} + +/* returned value need to be freed */ +char *get_iface_name_from_ethportsd(const char *ethport_name, int *ptype) +{ + char *prefix; + char *name = NULL; + int size; + int prefix_len; + int t = -1; + + if (ethport_name == NULL) { + goto out; + } + + prefix = ETHPORT_ALLOCATION_SD_PREFIX; + prefix_len = strlen(prefix); + if (0 != strncmp(ethport_name, prefix, prefix_len)) { + prefix = ETHPORT_CONNECTION_SD_PREFIX; + prefix_len = strlen(prefix); + if (0 != strncmp(ethport_name, prefix, prefix_len)) { + goto out; + } else { + t = EASD_TYPE_EC; + } + } else { + t = EASD_TYPE_EA; + } + size = strlen(ethport_name)-strlen(prefix)+1; + CU_MALLOC(name, size); + snprintf(name, size, "%s", ethport_name+prefix_len); + + out: + if (ptype != NULL) { + *ptype = t; + } + return name; +} + +int eth_iface_filter_cim_switch(const struct EthIface *piface, + void *nouse) +{ + if (piface->eth_type == ETH_TYPE_ETHER_BRIDGE) { + return 1; + } + return eth_iface_filter_peths(piface, nouse); +} + +int eth_iface_filter_cim_switch_for_name(const struct EthIface *piface, + void *name) +{ + int cim_switch_flag; + cim_switch_flag = eth_iface_filter_cim_switch(piface, NULL); + if (cim_switch_flag == 1) { + if (0 == strcmp(piface->name, name)) { + return 1; + } + } + return 0; +} + +/* returned value need to be freed */ +char *get_switch_name_from_iface(const char *iface_name) +{ + char *prefix = SWITCH_PREFIX; + char *name; + int size; + + size = strlen(iface_name)+strlen(prefix)+1; + CU_MALLOC(name, size); + snprintf(name, size, "%s%s", prefix, iface_name); + return name; +} + +/* returned value need to be freed */ +char *get_iface_name_from_switch(const char *switch_name) +{ + char *prefix = SWITCH_PREFIX; + char *name; + int size; + int prefix_len; + + prefix_len = strlen(prefix); + if (0 != strncmp(switch_name, prefix, prefix_len)) { + return NULL; + } + size = strlen(switch_name)-strlen(prefix)+1; + CU_MALLOC(name, size); + snprintf(name, size, "%s", switch_name+prefix_len); + return name; +} + +/* returned value need to be freed */ +char *get_ethport_name_from_iface(const char *iface_name) +{ + char *prefix; + char *name; + int size; + + if (iface_name == NULL) { + return NULL; + } + + prefix = ETHPORT_PREFIX; + size = strlen(iface_name)+strlen(prefix)+1; + CU_MALLOC(name, size); + snprintf(name, size, "%s%s", prefix, iface_name); + return name; +} + +/* returned value need to be freed */ +char *get_iface_name_from_ethport(const char *ethport_name) +{ + char *prefix = ETHPORT_PREFIX; + char *name = NULL; + int size; + int prefix_len; + + if (ethport_name == NULL) { + goto out; + } + + prefix = ETHPORT_PREFIX; + prefix_len = strlen(prefix); + if (0 != strncmp(ethport_name, prefix, prefix_len)) { + goto out; + } + size = strlen(ethport_name)-prefix_len+1; + CU_MALLOC(name, size); + snprintf(name, size, "%s", ethport_name+prefix_len); + + out: + return name; +} + +/* determine the CIM switch from the piface */ +int get_possible_bridge_name_for_cim_model(struct EthIface *piface, + char **pbr1name, char **pbr2name) +{ + char *br1_name; + char *br2_name; + if (piface->attach_bridge != NULL) { + br1_name = get_switch_name_from_iface(piface->attach_bridge); + } else if (piface->dep_ifname != NULL) { + br1_name = get_switch_name_from_iface(piface->dep_ifname); + } else if (piface->eth_type == ETH_TYPE_ETHER_PHYSICAL) { + br1_name = get_switch_name_from_iface(piface->name); + } else { + br1_name = NULL; + } + + if ((piface->attach_bridge != NULL) && (piface->dep_ifname != NULL)) { + br2_name = get_switch_name_from_iface(piface->dep_ifname); + } else if ((piface->attach_bridge != NULL) && + (piface->eth_type == ETH_TYPE_ETHER_PHYSICAL)) { + br2_name = get_switch_name_from_iface(piface->name); + } else { + br2_name = NULL; + } + + /* incase some pifaces such as "lo" have no parent nor attaching + bridge */ + if (br1_name == NULL) { + br1_name = get_switch_name_from_iface(piface->name); + } + *pbr1name = br1_name; + *pbr2name = br2_name; + return 1; +} + +CMPIStatus get_array_uint16_from_instance(const CMPIBroker *broker, + CMPIInstance *inst, + char *array_name, + int *ret_result, + int *ret_size, + int max_size) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIArray *array; + CMPICount array_size; + CMPIData elem; + int i, ret, count = 0; + + ret = cu_get_array_prop(inst, array_name, &array); + if (ret != CMPI_RC_OK) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "array property not found."); + CU_DEBUG("Failed to get array property %s.", array_name); + goto out; + } + array_size = CMGetArrayCount(array, &s); + if ((s.rc != CMPI_RC_OK) || (array_size > max_size) || + (array_size <= 0)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to get size of array property," + " or its size is 0 or too big."); + CU_DEBUG("failed in getting size of %s property.", array_name); + goto out; + } + for (i = 0; i < array_size; i++) { + elem = CMGetArrayElementAt(array, i, NULL); + if (CMIsNullValue(elem)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "NULL content of array property."); + CU_DEBUG("NULL content of %s property.", array_name); + goto out; + } + if (!(elem.type & CMPI_INTEGER)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "wrong type of array property."); + CU_DEBUG("wrong type of %s property.", array_name); + goto out; + } + ret_result[count] = elem.value.uint16; + count++; + } + out: + *ret_size = count; + return s; +} + +CMPIStatus get_array_string_from_instance(const CMPIBroker *broker, + CMPIInstance *inst, + char *array_name, + char **ret_result, + int *ret_size, + int max_size) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIArray *array; + CMPICount array_size; + CMPIData elem; + const char *str; + int i, ret, count = 0; + + ret = cu_get_array_prop(inst, array_name, &array); + if (ret != CMPI_RC_OK) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "array property not found."); + CU_DEBUG("Failed to get array property %s.", array_name); + goto out; + } + array_size = CMGetArrayCount(array, &s); + if ((s.rc != CMPI_RC_OK) || (array_size > max_size) || + (array_size <= 0)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to get size of array property," + " or its size is 0 or too big."); + CU_DEBUG("failed in getting size of %s property.", array_name); + goto out; + } + for (i = 0; i < array_size; i++) { + elem = CMGetArrayElementAt(array, i, NULL); + if (CMIsNullValue(elem)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "NULL content of array property."); + CU_DEBUG("NULL content of %s property.", array_name); + goto out; + } + str = NULL; + str = CMGetCharPtr(elem.value.string); + if (str == NULL) { + CU_DEBUG("Could not extract char pointer from " + "CMPIArray %s.", array_name); + goto out; + } + ret_result[count] = CU_STRDUP(str); + count++; + } + out: + *ret_size = count; + return s; +} diff --git a/libxkutil/network_model_helper.h b/libxkutil/network_model_helper.h new file mode 100644 index 0000000..6b3f151 --- /dev/null +++ b/libxkutil/network_model_helper.h @@ -0,0 +1,101 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NETWORK_MODEL_HELPER_H +#define NETWORK_MODEL_HELPER_H + +#include "network_parsing.h" + +#define EASD_TYPE_EA 1 +#define EASD_TYPE_EC 2 + +#define NETWORK_CLASS_PREFIX "Net" + +#define SWITCH_PREFIX "VS_" +#define VESSD_SYSTEM_PREFIX "Virt" +#define ETHPORT_PREFIX "EP_" +#define ETHPORT_ALLOCATION_SD_PREFIX "EA_" +#define ETHPORT_CONNECTION_SD_PREFIX "EC_" + +#define CONNECTION_VLAN_PREFIX "VLAN" + +#define CIM_NUM_NET_ETHERNET 2 +#define CIM_NUM_SWITCH_DEDICATED 38 +#define CIM_NUM_SWITCHPORT 30 +#define CIM_NUM_VLAN_MODE_TRUNK 5 +#define CIM_NUM_CONSUMERVISIBILITY_PASSEDTHROUGH 2 +#define CIM_NUM_CONSUMERVISIBILITY_VIRTUALIZED 3 + +char *get_switch_name_from_iface(const char *iface_name); +char *get_iface_name_from_switch(const char *switch_name); + +char *get_ethport_name_from_iface(const char *iface_name); +char *get_iface_name_from_ethport(const char *ethport_name); + +char *get_ethportsd_name_from_iface(const char *iface_name, const int type); +char *get_iface_name_from_ethportsd(const char *ethport_name, int *ptype); + +char *ep_id_to_easdea_id(const char *epid); +char *easdea_id_to_ep_id(const char *epid); +char *ep_id_to_easdec_id(const char *epid); +char *easdec_id_to_ep_id(const char *epid); + +char *vlanid_to_connection_name(const int id); +int vlanid_from_connection_name(const char *name); + +int eth_iface_filter_cim_switch(const struct EthIface *piface, + void *nouse); +int eth_iface_filter_cim_switch_for_name(const struct EthIface *piface, + void *name); +int eth_iface_filter_cim_ethport(const struct EthIface *piface, + void *nouse); +int eth_iface_filter_cim_ethport_for_name(const struct EthIface *piface, + void *name); + +int get_possible_bridge_name_for_cim_model(struct EthIface *piface, + char **pbr1name, char **pbr2name); + + +char *compare_and_switch_prefix(const char *orig_str, + const char *orig_prefix, + const char *dest_prefix); + +char *switch_device_id_prefix(const char *whole_id, + const char *orig_prefix, + const char *dest_prefix); + +/* other help function related to CIM */ +CMPIStatus get_array_uint16_from_instance(const CMPIBroker *broker, + CMPIInstance *inst, + char *array_name, + int *ret_result, + int *ret_size, + int max_size); + +CMPIStatus get_array_string_from_instance(const CMPIBroker *broker, + CMPIInstance *inst, + char *array_name, + char **ret_result, + int *ret_size, + int max_size); + + +#endif -- 1.7.1 From xiaxia347work at 163.com Tue Jan 31 13:20:18 2012 From: xiaxia347work at 163.com (xiaxia347work at 163.com) Date: Tue, 31 Jan 2012 21:20:18 +0800 Subject: [Libvirt-cim] [PATCH V6 4/7] vlan extention - CIM model add VESS Message-ID: <1328016018-31816-1-git-send-email-xiaxia347work@163.com> From: Wenchao Xia This patch add VESS according DSP1097. Signed-off-by: Wenchao Xia --- schema/VirtualEthernetSwitchSystem.mof | 10 + schema/VirtualEthernetSwitchSystem.registration | 3 + src/Virt_VirtualEthernetSwitchSystem.c | 478 +++++++++++++++++++++++ src/Virt_VirtualEthernetSwitchSystem.h | 52 +++ 4 files changed, 543 insertions(+), 0 deletions(-) create mode 100644 schema/VirtualEthernetSwitchSystem.mof create mode 100644 schema/VirtualEthernetSwitchSystem.registration create mode 100644 src/Virt_VirtualEthernetSwitchSystem.c create mode 100644 src/Virt_VirtualEthernetSwitchSystem.h diff --git a/schema/VirtualEthernetSwitchSystem.mof b/schema/VirtualEthernetSwitchSystem.mof new file mode 100644 index 0000000..6c43719 --- /dev/null +++ b/schema/VirtualEthernetSwitchSystem.mof @@ -0,0 +1,10 @@ +// Copyright IBM Corp. 2012 +[Description ( + "A class derived from CIM_ComputerSystem to represent " + "the Virtual Bridge on the host."), + Provider("cmpi::Virt_VirtualEthernetSwitchSystem") +] +class Net_VirtualEthernetSwitchSystem : CIM_ComputerSystem +{ + +}; diff --git a/schema/VirtualEthernetSwitchSystem.registration b/schema/VirtualEthernetSwitchSystem.registration new file mode 100644 index 0000000..ac94e7c --- /dev/null +++ b/schema/VirtualEthernetSwitchSystem.registration @@ -0,0 +1,3 @@ +# Copyright IBM Corp. 2012 +# Classname Namespace ProviderName ProviderModule ProviderTypes +Net_VirtualEthernetSwitchSystem root/virt Virt_VirtualEthernetSwitchSystem Virt_VirtualEthernetSwitchSystem instance method diff --git a/src/Virt_VirtualEthernetSwitchSystem.c b/src/Virt_VirtualEthernetSwitchSystem.c new file mode 100644 index 0000000..14fb340 --- /dev/null +++ b/src/Virt_VirtualEthernetSwitchSystem.c @@ -0,0 +1,478 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "Virt_VirtualEthernetSwitchSystem.h" +#include "device_parsing.h" +#include "network_model_helper.h" + +static const CMPIBroker *_BROKER; + +static int set_primary_for_switch(const CMPIBroker *broker, + const struct EthIface *piface, CMPIInstance *instance) +{ + char *name; + uint16_t dedicated; + CMPIArray *array; + CMPIStatus s = {CMPI_RC_OK, NULL}; + + if (piface->name == NULL) { + return 0; + } + + name = get_switch_name_from_iface(piface->name); + CMSetProperty(instance, "Name", + (CMPIValue *)name, CMPI_chars); + CMSetProperty(instance, "ElementName", + (CMPIValue *)name, CMPI_chars); + CU_FREE(name); + + array = CMNewArray(broker, 1, CMPI_uint16, &s); + if ((s.rc != CMPI_RC_OK) || (CMIsNullObject(array))) { + return 0; + } + dedicated = CIM_NUM_SWITCH_DEDICATED; + CMSetArrayElementAt(array, 0, &dedicated, CMPI_uint16); + CMSetProperty(instance, "Dedicated", + (CMPIValue *)&array, CMPI_uint16A); + + return 1; +} + +static int set_secondary_for_switch(const CMPIBroker *broker, + struct EthIface *piface, CMPIInstance *instance) +{ + int state; + if (piface->run_prop.status == ETH_STATE_INACTIVE) { + state = CIM_STATE_DISABLED; + } else if (piface->run_prop.status == ETH_STATE_ACTIVE) { + state = CIM_STATE_ENABLED; + } else { + state = CIM_STATE_UNKNOWN; + } + CMSetProperty(instance, "EnabledState", + (CMPIValue *)&state, CMPI_uint16); + CMSetProperty(instance, "RequestedState", + (CMPIValue *)&state, CMPI_uint16); + + return 1; +} + +/* Populate an instance with information from a switch */ +static CMPIStatus set_properties(const CMPIBroker *broker, + struct EthIface *piface, + const char *prefix, + CMPIInstance *instance) +{ + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; + char *errstr; + + if (!set_primary_for_switch(broker, piface, instance)) { + errstr = "failed to set primary properties for instance."; + CU_DEBUG("%s, iface name %s.", errstr, piface->name); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + if (!set_secondary_for_switch(broker, piface, instance)) { + errstr = "failed to set secondary properties for instance."; + CU_DEBUG("%s, iface name %s.", errstr, piface->name); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + cu_statusf(broker, &s, + CMPI_RC_OK, + ""); + + out: + return s; +} + +static CMPIStatus instance_from_switch(const CMPIBroker *broker, + const CMPIObjectPath *reference, + struct EthIface *piface, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + + inst = get_typed_instance(broker, + NETWORK_CLASS_PREFIX, + "VirtualEthernetSwitchSystem", + NAMESPACE(reference)); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to init VirtualEthernetSwitchSystem instance"); + goto out; + } + + s = set_properties(broker, + piface, + NETWORK_CLASS_PREFIX, + inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + *_inst = inst; + + out: + return s; +} + +CMPIStatus enum_switches(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const CMPIResult *results, + bool names_only) +{ + struct inst_list list; + CMPIStatus s = {CMPI_RC_OK, NULL}; + struct EthIfacesList ifaces_list; + int ret, i; + char *errstr; + + inst_list_init(&list); + eth_ifaceslist_init(&ifaces_list); + + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_cim_switch, NULL); + + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + eth_ifaceslist_print(&ifaces_list); + + i = 0; + while (i < ifaces_list.count) { + CMPIInstance *inst = NULL; + + s = instance_from_switch(broker, + reference, + ifaces_list.pifaces[i], + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(&list, inst); + i++; + } + + if (names_only) { + cu_return_instance_names(results, &list); + } else { + cu_return_instances(results, &list); + } + + out: + inst_list_free(&list); + eth_ifaceslist_uninit(&ifaces_list); + + return s; +} + +CMPIStatus get_switch_by_name(const CMPIBroker *broker, + const char *name, + const CMPIObjectPath *reference, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *eth_name = NULL; + char *errstr; + int ret; + struct EthIfacesList ifaces_list; + + eth_ifaceslist_init(&ifaces_list); + + eth_name = get_iface_name_from_switch(name); + if (eth_name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to convert switch_name"); + CU_DEBUG("switch name %s failed to convert.", name); + goto out; + } + + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_cim_switch_for_name, eth_name); + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + if (ifaces_list.count != 1) { + errstr = "expected switch not found."; + CU_DEBUG("%s\n", errstr); + eth_ifaceslist_print(&ifaces_list); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + s = instance_from_switch(broker, + reference, + ifaces_list.pifaces[0], + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + eth_ifaceslist_uninit(&ifaces_list); + CU_FREE(eth_name); + return s; +} + +CMPIStatus get_switch_by_ref(const CMPIBroker *broker, + const CMPIObjectPath *reference, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + const char *name = NULL; + + if (cu_get_str_path(reference, "Name", &name) != CMPI_RC_OK) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "No domain name specified"); + goto out; + } + + s = get_switch_by_name(broker, name, reference, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + s = cu_validate_ref(broker, reference, inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + + return s; +} + +static CMPIStatus __state_change(const CMPIBroker *broker, + const char *name, + uint16_t state, + const CMPIObjectPath *ref) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + struct EthIface iface; + int iface_state; + int ret; + char *errstr; + + eth_iface_init(&iface); + iface.name = get_iface_name_from_switch(name); + if (iface.name == NULL) { + errstr = "failed to get iface name."; + CU_DEBUG("for %s, %s.", name, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + if (state == CIM_STATE_ENABLED) { + iface_state = ETH_STATE_ACTIVE; + } else if (state == CIM_STATE_DISABLED) { + iface_state = ETH_STATE_INACTIVE; + } else { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_SUPPORTED, + "State not supported"); + goto out; + } + + /* TBD in next patch + ret = change_state_host_iface(&iface, iface_state); */ + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + + out: + eth_iface_uninit(&iface); + return s; +} + +static CMPIStatus EnumInstanceNames(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference) +{ + return enum_switches(_BROKER, reference, results, true); +} + +static CMPIStatus EnumInstances(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const char **properties) +{ + return enum_switches(_BROKER, reference, results, false); +} + +static CMPIStatus GetInstance(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const char **properties) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + + s = get_switch_by_ref(_BROKER, reference, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + CMReturnInstance(results, inst); + + out: + return s; +} + +DEFAULT_CI(); +DEFAULT_MI(); +DEFAULT_DI(); +DEFAULT_EQ(); +DEFAULT_INST_CLEANUP(); + +static CMPIStatus state_change(CMPIMethodMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const CMPIArgs *argsin, + CMPIArgs *argsout) +{ + CMPIStatus s; + CMPIInstance *prev_inst = NULL; + uint16_t state; + int ret; + const char *name = NULL; + uint32_t rc = 1; + + ret = cu_get_u16_arg(argsin, "RequestedState", &state); + if (ret != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_INVALID_PARAMETER, + "Invalid RequestedState"); + goto out; + } + + if (cu_get_str_path(reference, "Name", &name) != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Name key not specified"); + goto out; + } + + s = get_switch_by_name(_BROKER, name, reference, &prev_inst); + if (s.rc != CMPI_RC_OK || prev_inst == NULL) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_INVALID_PARAMETER, + "Unable to get instance for guest '%s'", + name); + goto out; + } + + s = __state_change(_BROKER, name, state, reference); + + if (s.rc == CMPI_RC_OK) { + rc = 0; + } + out: + CMReturnData(results, &rc, CMPI_uint32); + + return s; +} + +STD_InstanceMIStub(, + Virt_VirtualEthernetSwitchSystem, + _BROKER, + libvirt_cim_init()); + +static struct method_handler RequestStateChange = { + .name = "RequestStateChange", + .handler = state_change, + .args = {{"RequestedState", CMPI_uint16, false}, + {"TimeoutPeriod", CMPI_dateTime, true}, + ARG_END + } +}; + +static struct method_handler *my_handlers[] = { + &RequestStateChange, + NULL +}; + +STDIM_MethodMIStub(, + Virt_VirtualEthernetSwitchSystem, + _BROKER, + libvirt_cim_init(), + my_handlers); + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/Virt_VirtualEthernetSwitchSystem.h b/src/Virt_VirtualEthernetSwitchSystem.h new file mode 100644 index 0000000..de8587b --- /dev/null +++ b/src/Virt_VirtualEthernetSwitchSystem.h @@ -0,0 +1,52 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __VIRT_VIRTUALETHERNETSWITCHSYSTEM_H +#define __VIRT_VIRTUALETHERNETSWITCHSYSTEM_H + +#include "misc_util.h" + +CMPIStatus enum_switches(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const CMPIResult *results, + bool names_only); + +CMPIStatus get_switch_by_ref(const CMPIBroker *broker, + const CMPIObjectPath *reference, + CMPIInstance **_inst); + + +CMPIStatus get_switch_by_name(const CMPIBroker *broker, + const char *name, + const CMPIObjectPath *reference, + CMPIInstance **_inst); + + +#endif + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ -- 1.7.1 From xiaxia347work at 163.com Tue Jan 31 13:20:57 2012 From: xiaxia347work at 163.com (xiaxia347work at 163.com) Date: Tue, 31 Jan 2012 21:20:57 +0800 Subject: [Libvirt-cim] [PATCH V6 5/7] vlan extention - CIM model add VESSSD Message-ID: <1328016057-1834-1-git-send-email-xiaxia347work@163.com> From: Wenchao Xia This patch add VESSSD, VirtualSwitch are bridge and pNIC on host. Signed-off-by: Wenchao Xia --- schema/VirtualEthernetSwitchSystemSettingData.mof | 31 ++ ...ualEthernetSwitchSystemSettingData.registration | 3 + src/Virt_VESSSD.c | 382 ++++++++++++++++++++ src/Virt_VESSSD.h | 39 ++ 4 files changed, 455 insertions(+), 0 deletions(-) create mode 100644 schema/VirtualEthernetSwitchSystemSettingData.mof create mode 100644 schema/VirtualEthernetSwitchSystemSettingData.registration create mode 100644 src/Virt_VESSSD.c create mode 100644 src/Virt_VESSSD.h diff --git a/schema/VirtualEthernetSwitchSystemSettingData.mof b/schema/VirtualEthernetSwitchSystemSettingData.mof new file mode 100644 index 0000000..b6ecc65 --- /dev/null +++ b/schema/VirtualEthernetSwitchSystemSettingData.mof @@ -0,0 +1,31 @@ +// Copyright IBM Corp. 2012 + + +/* fix me: the libvirt-cim lacks parent class + "VirtualEthernetSwitchSettingData" defined in DSP1050 */ +[Description ( + "A class derived from Virt_VirtualEthernetSystemSettingData to represent " + "the config of ."), + Provider("cmpi::Virt_VESSSD") +] +class Net_VirtualEthernetSwitchSystemSettingData : CIM_VirtualSystemSettingData +{ + + [Description ("Virtual Switch System type number")] + string VirtualSystemType; + + string AssociatedResourcePool; + + uint16 VLAN_Connection[]; + + uint16 MaxNumAddress; + + uint16 EVBMode; + + uint16 STP; + + uint16 AutoStart; + + uint16 DHCP; + +}; diff --git a/schema/VirtualEthernetSwitchSystemSettingData.registration b/schema/VirtualEthernetSwitchSystemSettingData.registration new file mode 100644 index 0000000..1ba7e0c --- /dev/null +++ b/schema/VirtualEthernetSwitchSystemSettingData.registration @@ -0,0 +1,3 @@ +# Copyright IBM Corp. 2012 +# Classname Namespace ProviderName ProviderModule ProviderTypes +Net_VirtualEthernetSwitchSystemSettingData root/virt Virt_VESSSD Virt_VESSSD instance diff --git a/src/Virt_VESSSD.c b/src/Virt_VESSSD.c new file mode 100644 index 0000000..587741e --- /dev/null +++ b/src/Virt_VESSSD.c @@ -0,0 +1,382 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "cs_util.h" +#include "misc_util.h" +#include "device_parsing.h" + +#include "Virt_VESSSD.h" +#include "network_model_helper.h" + +static const CMPIBroker *_BROKER; + +static int set_primary_for_vesssd(const char *prefix, const CMPIBroker *broker, + struct EthIface *piface, CMPIInstance *instance) +{ + char *name, *vesssd_name; + int asret; + + if (piface->name == NULL) { + return 0; + } + + CMSetProperty(instance, "VirtualSystemType", + (CMPIValue *)"DMTF:VirtualEthernetSwitch", CMPI_chars); + + name = get_switch_name_from_iface(piface->name); + asret = asprintf(&vesssd_name, "%s:%s", prefix, name); + + CMSetProperty(instance, "InstanceID", + (CMPIValue *)vesssd_name, CMPI_chars); + CMSetProperty(instance, "ElementName", + (CMPIValue *)name, CMPI_chars); + CMSetProperty(instance, "VirtualSystemIdentifier", + (CMPIValue *)name, CMPI_chars); + CMSetProperty(instance, "VirtualSystemType", + (CMPIValue *)prefix, CMPI_chars); + + + + free(vesssd_name); + CU_FREE(name); + + return 1; +} + +static int set_secondary_for_vesssd(const CMPIBroker *broker, + struct EthIface *piface, CMPIInstance *instance) +{ + if (piface->eth_type == ETH_TYPE_ETHER_BRIDGE) { + CMSetProperty(instance, "STP", + (CMPIValue *)&piface->pbr_prop->STP, CMPI_uint16); + } + + if (piface->protocol_prop.ipv4_prop.DHCP >= 0) { + CMSetProperty(instance, "DHCP", + (CMPIValue *)&piface->protocol_prop.ipv4_prop.DHCP, + CMPI_uint16); + } + + if (piface->run_prop.boot_mode >= 0) { + CMSetProperty(instance, "AutoStart", + (CMPIValue *)&piface->run_prop.boot_mode, + CMPI_uint16); + } + + return 1; +} + +/* Populate an instance with information from a switch */ +static CMPIStatus set_properties(const CMPIBroker *broker, + struct EthIface *piface, + const char *prefix, + CMPIInstance *instance) +{ + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; + char *errstr; + + if (!set_primary_for_vesssd(prefix, broker, piface, instance)) { + errstr = "failed to set primary properties for instance."; + CU_DEBUG("%s, iface name %s.", errstr, piface->name); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + if (!set_secondary_for_vesssd(broker, piface, instance)) { + errstr = "failed to set secondary properties for instance."; + CU_DEBUG("%s, iface name %s.", errstr, piface->name); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + cu_statusf(broker, &s, + CMPI_RC_OK, + ""); + + out: + return s; +} + +static CMPIStatus instance_from_vesssd(const CMPIBroker *broker, + const CMPIObjectPath *reference, + struct EthIface *piface, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + + inst = get_typed_instance(broker, + NETWORK_CLASS_PREFIX, + "VirtualEthernetSwitchSystemSettingData", + NAMESPACE(reference)); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to init SwitchSystem instance"); + goto out; + } + + s = set_properties(broker, + piface, + VESSD_SYSTEM_PREFIX, + inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + return s; +} + +CMPIStatus enum_vesssd(const CMPIBroker *broker, + const CMPIObjectPath *reference, + struct inst_list *plist) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + struct EthIfacesList ifaces_list; + int ret, i; + char *errstr; + + eth_ifaceslist_init(&ifaces_list); + + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_cim_switch, NULL); + + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + i = 0; + while (i < ifaces_list.count) { + CMPIInstance *inst = NULL; + + s = instance_from_vesssd(broker, + reference, + ifaces_list.pifaces[i], + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + inst_list_add(plist, inst); + i++; + } + + out: + eth_ifaceslist_uninit(&ifaces_list); + + return s; +} + +static CMPIStatus return_enum_vesssd(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const CMPIResult *results, + bool names_only) +{ + struct inst_list list; + CMPIStatus s = {CMPI_RC_OK, NULL}; + inst_list_init(&list); + + s = enum_vesssd(broker, reference, &list); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + if (names_only) { + cu_return_instance_names(results, &list); + } else { + cu_return_instances(results, &list); + } + out: + inst_list_free(&list); + return s; +} + +CMPIStatus get_vesssd_by_name(const CMPIBroker *broker, + const char *name, + const CMPIObjectPath *reference, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *eth_name = NULL; + char *errstr; + int ret; + struct EthIfacesList ifaces_list; + + eth_ifaceslist_init(&ifaces_list); + + eth_name = get_iface_name_from_switch(name); + if (eth_name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to convert switch_name"); + CU_DEBUG("switch name %s failed to convert.", name); + goto out; + } + + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_cim_switch_for_name, eth_name); + + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + if (ifaces_list.count != 1) { + errstr = "expected switch not found."; + CU_DEBUG("%s\n", errstr); + eth_ifaceslist_print(&ifaces_list); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + s = instance_from_vesssd(broker, + reference, + ifaces_list.pifaces[0], + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + eth_ifaceslist_uninit(&ifaces_list); + CU_FREE(eth_name); + return s; +} + +CMPIStatus get_vesssd_by_ref(const CMPIBroker *broker, + const CMPIObjectPath *reference, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *name = NULL; + + if ((!parse_instanceid(reference, NULL, &name)) || (name == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_FOUND, + "No such instance (InstanceID)"); + goto out; + } + + s = get_vesssd_by_name(broker, name, reference, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + s = cu_validate_ref(broker, reference, inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + free(name); + + return s; +} + +static CMPIStatus EnumInstanceNames(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference) +{ + return return_enum_vesssd(_BROKER, reference, results, true); +} + +static CMPIStatus EnumInstances(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const char **properties) +{ + return return_enum_vesssd(_BROKER, reference, results, false); +} + +static CMPIStatus GetInstance(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const char **properties) +{ + CMPIStatus s; + CMPIInstance *inst = NULL; + + s = get_vesssd_by_ref(_BROKER, reference, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + CMReturnInstance(results, inst); + + out: + return s; +} + +DEFAULT_CI(); +DEFAULT_MI(); +DEFAULT_DI(); +DEFAULT_EQ(); +DEFAULT_INST_CLEANUP(); + +STD_InstanceMIStub(, + Virt_VESSSD, + _BROKER, + libvirt_cim_init()); + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/Virt_VESSSD.h b/src/Virt_VESSSD.h new file mode 100644 index 0000000..5105057 --- /dev/null +++ b/src/Virt_VESSSD.h @@ -0,0 +1,39 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __VIRT_VESSSD_H +#define __VIRT_VESSSD_H + + +CMPIStatus enum_vesssd(const CMPIBroker *broker, + const CMPIObjectPath *reference, + struct inst_list *plist); + +CMPIStatus get_vesssd_by_ref(const CMPIBroker *broker, + const CMPIObjectPath *reference, + CMPIInstance **_inst); + +CMPIStatus get_vesssd_by_name(const CMPIBroker *broker, + const char *name, + const CMPIObjectPath *reference, + CMPIInstance **_inst); + + +#endif -- 1.7.1 From xiaxia347work at 163.com Tue Jan 31 13:21:29 2012 From: xiaxia347work at 163.com (xiaxia347work at 163.com) Date: Tue, 31 Jan 2012 21:21:29 +0800 Subject: [Libvirt-cim] [PATCH V6 6/7] vlan extention - CIM model add EthernetPort Message-ID: <1328016089-4412-1-git-send-email-xiaxia347work@163.com> From: Wenchao Xia This patch add EthernetPort. EthernetPort is always a port on a switch, So eth0.10 is modeled as VS_eth0/EP_eth0.10, eth0 is modeled as VS_eth0/EP_Eth0. Signed-off-by: Wenchao Xia --- schema/EthernetPort.mof | 4 + schema/EthernetPort.registration | 3 + src/Virt_EthernetPort.c | 561 ++++++++++++++++++++++++++++++++++++++ src/Virt_EthernetPort.h | 58 ++++ 4 files changed, 626 insertions(+), 0 deletions(-) create mode 100644 schema/EthernetPort.mof create mode 100644 schema/EthernetPort.registration create mode 100644 src/Virt_EthernetPort.c create mode 100644 src/Virt_EthernetPort.h diff --git a/schema/EthernetPort.mof b/schema/EthernetPort.mof new file mode 100644 index 0000000..9d5e23e --- /dev/null +++ b/schema/EthernetPort.mof @@ -0,0 +1,4 @@ +// Copyright IBM Corp. 2012 +class Net_EthernetPort : CIM_EthernetPort +{ +}; diff --git a/schema/EthernetPort.registration b/schema/EthernetPort.registration new file mode 100644 index 0000000..e0e0f0c --- /dev/null +++ b/schema/EthernetPort.registration @@ -0,0 +1,3 @@ +# Copyright IBM Corp. 2012 +# Classname Namespace ProviderName ProviderModule ProviderTypes +Net_EthernetPort root/virt Virt_EthernetPort Virt_EthernetPort instance diff --git a/src/Virt_EthernetPort.c b/src/Virt_EthernetPort.c new file mode 100644 index 0000000..cdef910 --- /dev/null +++ b/src/Virt_EthernetPort.c @@ -0,0 +1,561 @@ +/* + * Copyright IBM Corp. 2007 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "misc_util.h" +#include "cs_util.h" +#include "device_parsing.h" +#include "network_model_helper.h" + +#include "Virt_EthernetPort.h" + +static const CMPIBroker *_BROKER; + +static int set_primary_for_ep(const CMPIBroker *broker, const char* prefix, + struct EthIface *piface, CMPIInstance *instance) +{ + char *eth_name, *ep_name; + const char *syscls_name = "Virt_VirtualEthernetSwitchSystem"; + int asret; + + if (piface->name == NULL) { + return 0; + } + + eth_name = get_ethport_name_from_iface(piface->name); + asret = asprintf(&ep_name, "%s/%s", prefix, eth_name); + + CMSetProperty(instance, "DeviceID", + (CMPIValue *)ep_name, CMPI_chars); + + CMSetProperty(instance, "InstanceID", + (CMPIValue *)ep_name, CMPI_chars); + + CMSetProperty(instance, "ElementName", + (CMPIValue *)eth_name, CMPI_chars); + CU_FREE(ep_name); + CU_FREE(eth_name); + + CMSetProperty(instance, "SystemCreationClassName", + (CMPIValue *)syscls_name, CMPI_chars); + + CMSetProperty(instance, "SystemName", + (CMPIValue *)prefix, CMPI_chars); + + return 1; +} + +static int set_secondary_for_ep(const CMPIBroker *broker, + struct EthIface *piface, CMPIInstance *instance) +{ + int state; + uint16_t cim_type; + CMPIArray *array; + CMPIStatus s; + CMPIString *str; + + if (piface->run_prop.status == ETH_STATE_INACTIVE) { + state = CIM_STATE_DISABLED; + } else if (piface->run_prop.status == ETH_STATE_ACTIVE) { + state = CIM_STATE_ENABLED; + } else { + state = CIM_STATE_UNKNOWN; + } + CMSetProperty(instance, "EnabledState", + (CMPIValue *)&state, CMPI_uint16); + CMSetProperty(instance, "RequestedState", + (CMPIValue *)&state, CMPI_uint16); + + cim_type = CIM_NUM_NET_ETHERNET; + CMSetProperty(instance, "LinkTechnology", + (CMPIValue *)&cim_type, CMPI_uint16); + + if (piface->mac != NULL) { + array = CMNewArray(broker, 1, CMPI_string, &s); + if ((s.rc != CMPI_RC_OK) || (CMIsNullObject(array))) { + CU_DEBUG("failed to create array."); + return 0; + } + str = CMNewString(broker, piface->mac, &s); + if ((s.rc != CMPI_RC_OK) || (CMIsNullObject(str))) { + CU_DEBUG("failed to create array."); + return 0; + } + + CMSetArrayElementAt(array, 0, &str, CMPI_string); + + CMSetProperty(instance, "NetworkAddresses", + (CMPIValue *)&array, CMPI_stringA); + } + + return 1; +} + +static CMPIStatus set_properties(const CMPIBroker *broker, + struct EthIface *piface, + const char *prefix, + CMPIInstance *instance) +{ + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; + char *errstr = NULL; + + if (!set_primary_for_ep(broker, prefix, piface, instance)) { + errstr = "failed to set primary properties for instance."; + CU_DEBUG("%s, iface name %s.", errstr, piface->name); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + if (!set_secondary_for_ep(broker, piface, instance)) { + errstr = "failed to set secondary properties for instance."; + CU_DEBUG("%s, iface name %s.", errstr, piface->name); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + cu_statusf(broker, &s, + CMPI_RC_OK, + ""); + + out: + return s; +} + + +static CMPIStatus instance_from_ep_build(const CMPIBroker *broker, + struct EthIface *piface, + const char *prefix, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst) +{ + CMPIInstance *inst = NULL; + CMPIStatus s = {CMPI_RC_OK, NULL}; + const char *keys[] = {"InstanceID", NULL}; + + inst = get_typed_instance(broker, + NETWORK_CLASS_PREFIX, + "EthernetPort", + NAMESPACE(reference)); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to init ep instance"); + goto out; + } + + s = CMSetPropertyFilter(inst, properties, keys); + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("Unable to set property filter: %d", s.rc); + } + + s = set_properties(broker, + piface, + prefix, + inst); + + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + return s; +} + + +static CMPIStatus instance_from_ep(const CMPIBroker *broker, + struct EthIface *piface, + const char *vsname, + const CMPIObjectPath *reference, + const char **properties, + struct inst_list *plist) +{ + + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *br1_name = NULL, *br2_name = NULL; + + get_possible_bridge_name_for_cim_model(piface, &br1_name, &br2_name); + if (br1_name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to find any bridge for the port."); + CU_DEBUG("failed to find any bridge for the port %s.", + piface->name); + goto out; + } + + /* building up the instance */ + if ((vsname == NULL) || (0 == strcmp(vsname, br1_name))) { + inst = NULL; + s = instance_from_ep_build(broker, + piface, + br1_name, + reference, + properties, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(plist, inst); + } + + /* following is to make it comform to CIM profile which require two + ethports connectted to pNIC and vswitch, but we have only one piface + on linux indicating it is connected to pNIC and bridge at sametime */ + if (br2_name == NULL) { + goto out; + } + + if ((vsname == NULL) || (0 == strcmp(vsname, br2_name))) { + inst = NULL; + s = instance_from_ep_build(broker, + piface, + br2_name, + reference, + properties, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(plist, inst); + } + + + out: + CU_FREE(br1_name); + CU_FREE(br2_name); + return s; +} + +CMPIStatus get_ep_by_name(const CMPIBroker *broker, + const char *prefix, + const char *name, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *eth_name = NULL; + char *dest = NULL; + char *errstr; + int ret; + struct EthIfacesList ifaces_list; + struct inst_list list; + + eth_ifaceslist_init(&ifaces_list); + inst_list_init(&list); + + eth_name = get_iface_name_from_ethport(name); + if (eth_name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to convert instance name"); + CU_DEBUG("ethport name %s failed to convert.", name); + goto out; + } + + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_cim_ethport_for_name, eth_name); + + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + if (ifaces_list.count != 1) { + errstr = "expected ethport not found."; + CU_DEBUG("%s\n", errstr); + eth_ifaceslist_print(&ifaces_list); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + inst = NULL; + s = instance_from_ep(broker, + ifaces_list.pifaces[0], + prefix, + reference, + properties, + &list); + + if (s.rc != CMPI_RC_OK) { + goto out; + } + + if (list.cur == 0) { + CU_DEBUG("%d instance found, expect is 1.", list.cur); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "no such instance."); + goto out; + } + + if (list.cur > 1) { + CU_DEBUG("%d instance found, expect is 1.", list.cur); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "instance found do not match expectation"); + goto out; + } + + *_inst = list.list[0]; + list.list[0] = NULL; + + out: + eth_ifaceslist_uninit(&ifaces_list); + inst_list_free(&list); + CU_FREE(eth_name); + CU_FREE(dest); + return s; +} + +CMPIStatus get_ep_by_id(const CMPIBroker *broker, + const char *id, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + char *prefix = NULL; + char *suffix = NULL; + if (id == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_INVALID_PARAMETER, + "ID is NULL'", id); + } + if (!parse_fq_devid(id, &prefix, &suffix) || (prefix == NULL) || + (suffix == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_INVALID_PARAMETER, + "Invalid InstanceID `%s'", id); + goto out; + } + s = get_ep_by_name(broker, prefix, suffix, reference, + properties, _inst); + + out: + CU_FREE(prefix); + CU_FREE(suffix); + return s; +} + +CMPIStatus get_ep_by_ref(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *name = NULL; + char *prefix = NULL; + const char *id; + + if (cu_get_str_path(reference, "DeviceID", &id) != CMPI_RC_OK) { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_FOUND, + "No such instance (InstanceID)"); + goto out; + } + if ((!parse_fq_devid(id, &prefix, &name)) || + (name == NULL) || (prefix == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_FOUND, + "Failed to translate (InstanceID)"); + goto out; + } + + s = get_ep_by_name(broker, prefix, name, reference, + properties, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + s = cu_validate_ref(broker, reference, inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + free(name); + free(prefix); + + return s; +} + + +CMPIStatus enum_eps(const CMPIBroker *broker, + const char *ref_vsname, + const CMPIObjectPath *reference, + const char **properties, + struct inst_list *plist) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + struct EthIfacesList ifaces_list; + int ret, i; + char *errstr; + + eth_ifaceslist_init(&ifaces_list); + + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_cim_ethport, NULL); + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + CU_DEBUG("enum ep, found following devices.") + eth_ifaceslist_print(&ifaces_list); + + i = 0; + while (i < ifaces_list.count) { + s = instance_from_ep(broker, + ifaces_list.pifaces[i], + ref_vsname, + reference, + properties, + plist); + i++; + /* this should never fail */ + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("unexpected fail."); + break; + } + } + + + out: + eth_ifaceslist_uninit(&ifaces_list); + + return s; +} + +static CMPIStatus return_enum_eps(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const CMPIResult *results, + const char **properties, + const bool names_only) +{ + struct inst_list list; + CMPIStatus s = {CMPI_RC_OK, NULL}; + inst_list_init(&list); + s = enum_eps(broker, NULL, reference, properties, &list); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + if (names_only) { + cu_return_instance_names(results, &list); + } else { + cu_return_instances(results, &list); + } + + out: + inst_list_free(&list); + return s; +} + +static CMPIStatus EnumInstanceNames(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference) +{ + return return_enum_eps(_BROKER, reference, results, NULL, true); +} + +static CMPIStatus EnumInstances(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const char **properties) +{ + + return return_enum_eps(_BROKER, reference, results, properties, false); +} + +static CMPIStatus GetInstance(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *ref, + const char **properties) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + + s = get_ep_by_ref(_BROKER, ref, properties, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + CMReturnInstance(results, inst); + + out: + return s; +} + +DEFAULT_CI(); +DEFAULT_MI(); +DEFAULT_DI(); +DEFAULT_INST_CLEANUP(); +DEFAULT_EQ(); + +STD_InstanceMIStub(, + Virt_EthernetPort, + _BROKER, + libvirt_cim_init()); + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/Virt_EthernetPort.h b/src/Virt_EthernetPort.h new file mode 100644 index 0000000..f474af2 --- /dev/null +++ b/src/Virt_EthernetPort.h @@ -0,0 +1,58 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wencao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __VIRT_ETHERNETPORT_H +#define __VIRT_ETHERNETPORT_H + +CMPIStatus enum_eps(const CMPIBroker *broker, + const char *ref_vsname, + const CMPIObjectPath *reference, + const char **properties, + struct inst_list *plist); + +CMPIStatus get_ep_by_name(const CMPIBroker *broker, + const char *prefix, + const char *name, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst); + +CMPIStatus get_ep_by_id(const CMPIBroker *broker, + const char *id, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst); + +CMPIStatus get_ep_by_ref(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst); + +#endif + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ -- 1.7.1 From xiaxia347work at 163.com Tue Jan 31 13:22:01 2012 From: xiaxia347work at 163.com (xiaxia347work at 163.com) Date: Tue, 31 Jan 2012 21:22:01 +0800 Subject: [Libvirt-cim] [PATCH V6 7/7] vlan extention - CIM model add EASD Message-ID: <1328016121-6418-1-git-send-email-xiaxia347work@163.com> From: Wenchao Xia Add EASD for EthernetPort. According DSP1097, There are two kinds of EASD: EA stands for Settings of EthernetPort, EC stands for Settings for Connection between EthernetPort. Signed-off-by: Wenchao Xia --- schema/EthernetPortAllocationSettingData.mof | 22 + .../EthernetPortAllocationSettingData.registration | 3 + src/Virt_EASD.c | 709 ++++++++++++++++++++ src/Virt_EASD.h | 59 ++ 4 files changed, 793 insertions(+), 0 deletions(-) create mode 100644 schema/EthernetPortAllocationSettingData.mof create mode 100644 schema/EthernetPortAllocationSettingData.registration create mode 100644 src/Virt_EASD.c create mode 100644 src/Virt_EASD.h diff --git a/schema/EthernetPortAllocationSettingData.mof b/schema/EthernetPortAllocationSettingData.mof new file mode 100644 index 0000000..726bb1f --- /dev/null +++ b/schema/EthernetPortAllocationSettingData.mof @@ -0,0 +1,22 @@ +// Copyright IBM Corp. 2012 + +[Description ("Virtutal EthernetPort Setting Data"), + Provider("cmpi::Virt_EASD") +] + +class Net_EthernetPortAllocationSettingData : CIM_EthernetPortAllocationSettingData +{ + uint16 PortVID; + uint16 DesiredEndPointMode; + + [Description("VLAN type of the port, " + "Now only support IEEE 802.1.q."), + ValueMap { "0", "1", "2", "3" }, + Values { "Not VLAN", "IEEE 802.1.q", "IEEE 802.1.qbg", "IEEE 802.1.qbh" }] + uint16 VLANType; + + uint16 AutoStart; + + uint16 DHCP; + +}; diff --git a/schema/EthernetPortAllocationSettingData.registration b/schema/EthernetPortAllocationSettingData.registration new file mode 100644 index 0000000..8925739 --- /dev/null +++ b/schema/EthernetPortAllocationSettingData.registration @@ -0,0 +1,3 @@ +# Copyright IBM Corp. 2012 +# Classname Namespace ProviderName ProviderModule ProviderTypes +Net_EthernetPortAllocationSettingData root/virt Virt_EASD Virt_EASD instance diff --git a/src/Virt_EASD.c b/src/Virt_EASD.c new file mode 100644 index 0000000..bdcf125 --- /dev/null +++ b/src/Virt_EASD.c @@ -0,0 +1,709 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "misc_util.h" +#include "cs_util.h" +#include "device_parsing.h" +#include "network_model_helper.h" + +#include "Virt_EASD.h" + +static const CMPIBroker *_BROKER; + +static int set_primary_for_easd(const CMPIBroker *broker, const char* prefix, + struct EthIface *piface, int type, CMPIInstance *instance) +{ + char *eth_name, *easd_name; + int asret; + uint16_t res_type = CIM_NUM_SWITCHPORT; + uint16_t vlan_mode; + + if (piface->name == NULL) { + return 0; + } + + eth_name = get_ethportsd_name_from_iface(piface->name, type); + asret = asprintf(&easd_name, "%s/%s", prefix, eth_name); + + CMSetProperty(instance, "InstanceID", + (CMPIValue *)easd_name, CMPI_chars); + CMSetProperty(instance, "ElementName", + (CMPIValue *)eth_name, CMPI_chars); + CU_FREE(easd_name); + CU_FREE(eth_name); + + CMSetProperty(instance, "ResourceType", + (CMPIValue *)&res_type, CMPI_uint16); + + if (piface->eth_type == ETH_TYPE_ETHER_PHYSICAL) { + vlan_mode = CIM_NUM_VLAN_MODE_TRUNK; + CMSetProperty(instance, "DesiredEndPointMode", + (CMPIValue *)&vlan_mode, CMPI_uint16); + } + + + if (piface->mac != NULL) { + CMSetProperty(instance, "Address", + (CMPIValue *)piface->mac, CMPI_chars); + } + + return 1; +} + +static int set_secondary_for_easd(const CMPIBroker *broker, + struct EthIface *piface, CMPIInstance *instance) +{ + struct VLAN_Prop *pvlan; + struct VLAN_Prop_8021q *pvlan8021q; + uint16_t vid; + CMPIArray *conn_array; + CMPIString *cm_str; + char *str = NULL; + CMPIStatus s; + uint16_t vlantype = 0; + uint16_t visibility = CIM_NUM_CONSUMERVISIBILITY_VIRTUALIZED; + + if (piface->eth_type == ETH_TYPE_ETHER_PHYSICAL) { + visibility = CIM_NUM_CONSUMERVISIBILITY_PASSEDTHROUGH; + } + CMSetProperty(instance, "ConsumerVisibility", + (CMPIValue *)&visibility, CMPI_uint16); + + if (piface->protocol_prop.ipv4_prop.DHCP >= 0) { + CMSetProperty(instance, "DHCP", + (CMPIValue *)&piface->protocol_prop.ipv4_prop.DHCP, + CMPI_uint16); + } + + if (piface->run_prop.boot_mode >= 0) { + CMSetProperty(instance, "AutoStart", + (CMPIValue *)&piface->run_prop.boot_mode, + CMPI_uint16); + } + + if ((piface->eth_type != ETH_TYPE_ETHER_VLAN) || + (piface->pvlan_prop == NULL)) { + goto out; + } + pvlan = piface->pvlan_prop; + + if (pvlan->vlan_type == VLAN_TYPE_802_1_Q) { + pvlan8021q = &(pvlan->props.prop_8021q); + vid = pvlan8021q->vlan_id; + CMSetProperty(instance, "PortVID", + (CMPIValue *)&vid, CMPI_uint16); + + str = vlanid_to_connection_name(vid); + conn_array = CMNewArray(broker, 1, CMPI_string, &s); + if ((s.rc != CMPI_RC_OK) || (str == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Error creating Connection " + "list and its string"); + CU_DEBUG("CMNewArray or string creation failed"); + goto out; + } + cm_str = CMNewString(broker, str, &s); + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("Error creating CMPIString"); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Error creating CMPIString for " + "BootDevices item"); + + goto out; + } + CMSetArrayElementAt(conn_array, 0, (CMPIValue *)&cm_str, + CMPI_string); + CMSetProperty(instance, "Connection", + (CMPIValue *)&conn_array, CMPI_stringA); + + vlantype = 1; + } + CMSetProperty(instance, "VLANType", + (CMPIValue *)&vlantype, CMPI_uint16); + +out: + CU_FREE(str); + return 1; +} + +static CMPIStatus add_conn_properties(const CMPIBroker *broker, + struct EthIface *piface, + const char *prefix, + const char *dest, + CMPIInstance *instance) +{ + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; + char *eth_name, *easd_name; + int asret; + CMPIArray *array; + CMPIString *tmp; + + if (piface->name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "device name not set"); + goto out; + } + if (dest == NULL) { + CU_DEBUG("warn: connection dest is NULL."); + } + + eth_name = get_ethportsd_name_from_iface(piface->name, EASD_TYPE_EA); + asret = asprintf(&easd_name, "%s:%s", prefix, eth_name); + CMSetProperty(instance, "Parent", + (CMPIValue *)easd_name, CMPI_chars); + CU_FREE(easd_name); + CU_FREE(eth_name); + + array = CMNewArray(broker, 1, CMPI_string, &s); + tmp = CMNewString(broker, dest, NULL); + CMSetArrayElementAt(array, 0, &(tmp), CMPI_string); + CMSetProperty(instance, "HostResource", + (CMPIValue *)&array, CMPI_stringA); + + + out: + return s; +} + +static CMPIStatus set_properties(const CMPIBroker *broker, + struct EthIface *piface, + const char *prefix, + const char *dest, + int type, + CMPIInstance *instance) +{ + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; + char *errstr; + + if (!set_primary_for_easd(broker, prefix, piface, type, instance)) { + errstr = "failed to set primary properties for instance."; + CU_DEBUG("%s, iface name %s.", errstr, piface->name); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + if (type == EASD_TYPE_EA) { + if (!set_secondary_for_easd(broker, piface, instance)) { + errstr = "failed to set secondary properties" + " for instance."; + CU_DEBUG("%s, iface name %s.", errstr, piface->name); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + } else { + s = add_conn_properties(broker, + piface, + prefix, + dest, + instance); + if (s.rc != CMPI_RC_OK) { + goto out; + } + } + + cu_statusf(broker, &s, + CMPI_RC_OK, + ""); + + out: + return s; +} + +static CMPIStatus instance_from_easd_build(const CMPIBroker *broker, + struct EthIface *piface, + const char *prefix, + const char *dest, + int type, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst) +{ + CMPIInstance *inst = NULL; + CMPIStatus s = {CMPI_RC_OK, NULL}; + const char *keys[] = {"InstanceID", NULL}; + + inst = get_typed_instance(broker, + NETWORK_CLASS_PREFIX, + "EthernetPortAllocationSettingData", + NAMESPACE(reference)); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to init SwitchSystem instance"); + goto out; + } + + + s = CMSetPropertyFilter(inst, properties, keys); + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("Unable to set property filter: %d", s.rc); + } + + s = set_properties(broker, + piface, + prefix, + dest, + type, + inst); + + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + return s; +} + +/* vsname and req_type are filter conditions */ +static CMPIStatus instance_from_easd(const CMPIBroker *broker, + struct EthIface *piface, + const char *vsname, + int req_type, + const CMPIObjectPath *reference, + const char **properties, + struct inst_list *plist) +{ + + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *br1_name = NULL, *br2_name = NULL; + + CU_DEBUG("enter instance_for_easd with vsname %s, type %d.", + vsname, req_type); + get_possible_bridge_name_for_cim_model(piface, &br1_name, &br2_name); + if (br1_name == NULL) { + CU_DEBUG("failed to find any bridge for the port %s.", + piface->name); + } + + /* building the EA instance */ + if (!(req_type&EASD_TYPE_EA)) { + goto ea_build_end; + } + if ((vsname == NULL) || (br1_name == NULL) || + (0 == strcmp(vsname, br1_name))) { + inst = NULL; + s = instance_from_easd_build(broker, + piface, + br1_name, + NULL, + EASD_TYPE_EA, + reference, + properties, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(plist, inst); + } + + /* following is to make it comform to CIM profile which require two + ethports connectted to pNIC and vswitch, but we have only one piface + on linux indicating it is connected to pNIC and bridge at sametime */ + if (br2_name == NULL) { + goto out; + } + + if ((vsname == NULL) || (0 == strcmp(vsname, br2_name))) { + inst = NULL; + s = instance_from_easd_build(broker, + piface, + br2_name, + NULL, + EASD_TYPE_EA, + reference, + properties, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(plist, inst); + } + ea_build_end: + + /* building the EC instance */ + if (!(req_type&EASD_TYPE_EC)) { + goto ec_build_end; + } + if ((br1_name == NULL) || (br2_name == NULL)) { + goto ec_build_end; + } + /* connection exist, so a EC_easd should be added for each bridge */ + if ((vsname == NULL) || (0 == strcmp(vsname, br1_name))) { + inst = NULL; + s = instance_from_easd_build(broker, + piface, + br1_name, + br2_name, + EASD_TYPE_EC, + reference, + properties, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(plist, inst); + } + if ((vsname == NULL) || (0 == strcmp(vsname, br2_name))) { + inst = NULL; + s = instance_from_easd_build(broker, + piface, + br2_name, + br1_name, + EASD_TYPE_EC, + reference, + properties, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(plist, inst); + } + ec_build_end: + + out: + CU_FREE(br1_name); + CU_FREE(br2_name); + return s; +} + +CMPIStatus get_easd_by_name(const CMPIBroker *broker, + const char *prefix, + const char *name, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *eth_name = NULL; + char *dest = NULL; + char *errstr; + int ret; + int type; + struct EthIfacesList ifaces_list; + struct inst_list list; + + CU_DEBUG("####prefix %s", prefix); + eth_ifaceslist_init(&ifaces_list); + inst_list_init(&list); + + eth_name = get_iface_name_from_ethportsd(name, &type); + if (eth_name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to convert instance name"); + CU_DEBUG("ethport name %s failed to convert.", name); + goto out; + } + + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_cim_ethport_for_name, eth_name); + + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + if (ifaces_list.count != 1) { + errstr = "expected ethport not found."; + CU_DEBUG("%d ethportd found.", ifaces_list.count); + eth_ifaceslist_print(&ifaces_list); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + inst = NULL; + s = instance_from_easd(broker, + ifaces_list.pifaces[0], + prefix, + type, + reference, + properties, + &list); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + if (list.cur == 0) { + CU_DEBUG("%d instance found, expect is 1.", list.cur); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "no such instance."); + goto out; + } + + if (list.cur > 1) { + CU_DEBUG("%d instance found, expect is 1.", list.cur); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "instance found do not match expectation"); + goto out; + } + + *_inst = list.list[0]; + list.list[0] = NULL; + + out: + eth_ifaceslist_uninit(&ifaces_list); + inst_list_free(&list); + CU_FREE(eth_name); + CU_FREE(dest); + return s; +} + +CMPIStatus get_easd_by_id(const CMPIBroker *broker, + const char *id, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + char *prefix = NULL; + char *suffix = NULL; + if (id == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_INVALID_PARAMETER, + "ID is NULL'", id); + } + if (!parse_fq_devid(id, &prefix, &suffix) || (prefix == NULL) || + (suffix == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_INVALID_PARAMETER, + "Invalid InstanceID `%s'", id); + goto out; + } + s = get_easd_by_name(broker, prefix, suffix, reference, + properties, _inst); + + out: + CU_FREE(prefix); + CU_FREE(suffix); + return s; +} + +CMPIStatus get_easd_by_ref(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *name = NULL; + char *prefix = NULL; + const char *id; + + if (cu_get_str_path(reference, "InstanceID", &id) != CMPI_RC_OK) { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_FOUND, + "No such instance (InstanceID)"); + goto out; + } + if ((!parse_fq_devid(id, &prefix, &name)) || + (name == NULL) || (prefix == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_FOUND, + "Failed to translate (InstanceID)"); + goto out; + } + + s = get_easd_by_name(broker, prefix, name, reference, + properties, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + s = cu_validate_ref(broker, reference, inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + free(name); + free(prefix); + + return s; +} + + +CMPIStatus enum_easds(const CMPIBroker *broker, + const char *ref_vsname, + const CMPIObjectPath *reference, + const char **properties, + struct inst_list *plist) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + struct EthIfacesList ifaces_list; + int ret, i; + char *errstr; + + eth_ifaceslist_init(&ifaces_list); + + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_cim_ethport, NULL); + if (ret != 1) { + errstr = get_host_iface_error_reason(ret); + CU_DEBUG("error num %d returned, reason %s.", ret, errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + CU_DEBUG("enum easd, found following devices.") + eth_ifaceslist_print(&ifaces_list); + + i = 0; + while (i < ifaces_list.count) { + s = instance_from_easd(broker, + ifaces_list.pifaces[i], + ref_vsname, + EASD_TYPE_EA|EASD_TYPE_EC, + reference, + properties, + plist); + i++; + /* this should never fail */ + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("unexpected fail."); + break; + } + } + + + out: + eth_ifaceslist_uninit(&ifaces_list); + + return s; +} + +static CMPIStatus return_enum_easds(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const CMPIResult *results, + const char **properties, + const bool names_only) +{ + struct inst_list list; + CMPIStatus s = {CMPI_RC_OK, NULL}; + inst_list_init(&list); + s = enum_easds(broker, NULL, reference, properties, &list); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + if (names_only) { + cu_return_instance_names(results, &list); + } else { + cu_return_instances(results, &list); + } + + out: + inst_list_free(&list); + return s; +} + +static CMPIStatus EnumInstanceNames(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference) +{ + return return_enum_easds(_BROKER, reference, results, + NULL, true); +} + +static CMPIStatus EnumInstances(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const char **properties) +{ + + return return_enum_easds(_BROKER, reference, results, + properties, false); +} + +static CMPIStatus GetInstance(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *ref, + const char **properties) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + + s = get_easd_by_ref(_BROKER, ref, properties, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + CMReturnInstance(results, inst); + + out: + return s; +} + +DEFAULT_CI(); +DEFAULT_MI(); +DEFAULT_DI(); +DEFAULT_INST_CLEANUP(); +DEFAULT_EQ(); + +STD_InstanceMIStub(, + Virt_EASD, + _BROKER, + libvirt_cim_init()); + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/Virt_EASD.h b/src/Virt_EASD.h new file mode 100644 index 0000000..f9d13ec --- /dev/null +++ b/src/Virt_EASD.h @@ -0,0 +1,59 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __VIRT_EASD_H +#define __VIRT_EASD_H + +CMPIStatus enum_easds(const CMPIBroker *broker, + const char *ref_vsname, + const CMPIObjectPath *reference, + const char **properties, + struct inst_list *plist); + +CMPIStatus get_easd_by_name(const CMPIBroker *broker, + const char *prefix, + const char *name, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst); + +CMPIStatus get_easd_by_id(const CMPIBroker *broker, + const char *id, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst); + +CMPIStatus get_easd_by_ref(const CMPIBroker *broker, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst); + + +#endif + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ -- 1.7.1 From xiaxia347work at 163.com Tue Jan 31 13:19:45 2012 From: xiaxia347work at 163.com (xiaxia347work at 163.com) Date: Tue, 31 Jan 2012 21:19:45 +0800 Subject: [Libvirt-cim] [PATCH V6 3/7] vlan extention - CIM model Makefile change Message-ID: <1328015985-29748-1-git-send-email-xiaxia347work@163.com> From: Wenchao Xia This patch change the Makefile to add new classes. Signed-off-by: Wenchao Xia --- Makefile.am | 14 ++++++++++++-- src/Makefile.am | 23 ++++++++++++++++++++--- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Makefile.am b/Makefile.am index 94dc5f3..86c155b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -63,7 +63,12 @@ MOFS = \ $(top_srcdir)/schema/EntriesInFilterList.mof \ $(top_srcdir)/schema/NestedFilterList.mof \ $(top_srcdir)/schema/AppliedFilterList.mof \ - $(top_srcdir)/schema/HostedFilterList.mof + $(top_srcdir)/schema/HostedFilterList.mof \ + $(top_srcdir)/schema/HostedFilterList.mof \ + $(top_srcdir)/schema/VirtualEthernetSwitchSystem.mof \ + $(top_srcdir)/schema/VirtualEthernetSwitchSystemSettingData.mof \ + $(top_srcdir)/schema/EthernetPort.mof \ + $(top_srcdir)/schema/EthernetPortAllocationSettingData.mof INTEROP_MOFS = \ $(top_srcdir)/schema/ComputerSystem.mof \ @@ -150,7 +155,12 @@ REGS = \ $(top_srcdir)/schema/EntriesInFilterList.registration \ $(top_srcdir)/schema/NestedFilterList.registration \ $(top_srcdir)/schema/AppliedFilterList.registration \ - $(top_srcdir)/schema/HostedFilterList.registration + $(top_srcdir)/schema/HostedFilterList.registration \ + $(top_srcdir)/schema/HostedFilterList.registration \ + $(top_srcdir)/schema/VirtualEthernetSwitchSystem.registration \ + $(top_srcdir)/schema/VirtualEthernetSwitchSystemSettingData.registration \ + $(top_srcdir)/schema/EthernetPort.registration \ + $(top_srcdir)/schema/EthernetPortAllocationSettingData.registration INTEROP_REGS = \ $(top_srcdir)/schema/RegisteredProfile.registration \ diff --git a/src/Makefile.am b/src/Makefile.am index c28dc9a..5570b13 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,11 +24,16 @@ noinst_HEADERS = profiles.h svpc_types.h \ Virt_ConsoleRedirectionServiceCapabilities.h \ Virt_KVMRedirectionSAP.h \ Virt_FilterList.h \ - Virt_FilterEntry.h + Virt_FilterEntry.h \ + Virt_VirtualEthernetSwitchSystem.h \ + Virt_VESSSD.h \ + Virt_EthernetPort.h \ + Virt_EASD.h XKUADD = $(top_builddir)/libxkutil/libxkutil.la +NTWADD = $(top_builddir)/libnetwork/libnetwork.la -CFLAGS += -I$(top_srcdir)/libxkutil $(CFLAGS_STRICT) +CFLAGS += -I$(top_srcdir)/libxkutil -I$(top_srcdir)/libnetwork $(CFLAGS_STRICT) AM_LDFLAGS = $(XKUADD) \ -version-info @VERSION_INFO@ @@ -85,7 +90,11 @@ provider_LTLIBRARIES = libVirt_ComputerSystem.la \ libVirt_EntriesInFilterList.la \ libVirt_NestedFilterList.la \ libVirt_HostedFilterList.la \ - libVirt_AppliedFilterList.la + libVirt_AppliedFilterList.la \ + libVirt_VirtualEthernetSwitchSystem.la \ + libVirt_VESSSD.la \ + libVirt_EthernetPort.la \ + libVirt_EASD.la libVirt_ComputerSystem_la_SOURCES = Virt_ComputerSystem.c libVirt_ComputerSystem_la_DEPENDENCIES = libVirt_VirtualSystemSnapshotService.la @@ -274,3 +283,11 @@ libVirt_HostedFilterList_la_LIBADD = -lVirt_HostSystem -lVirt_FilterList libVirt_AppliedFilterList_la_DEPENDENCIES = libVirt_Device.la libVirt_FilterList.la libVirt_AppliedFilterList_la_SOURCES = Virt_AppliedFilterList.c libVirt_AppliedFilterList_la_LIBADD = -lVirt_Device -lVirt_FilterList + +libVirt_VirtualEthernetSwitchSystem_la_SOURCES = Virt_VirtualEthernetSwitchSystem.c + +libVirt_VESSSD_la_SOURCES = Virt_VESSSD.c + +libVirt_EthernetPort_la_SOURCES = Virt_EthernetPort.c + +libVirt_EASD_la_SOURCES = Virt_EASD.c -- 1.7.1 From xiaxia347work at 163.com Tue Jan 31 14:51:25 2012 From: xiaxia347work at 163.com (xiaxia347work) Date: Tue, 31 Jan 2012 22:51:25 +0800 Subject: [Libvirt-cim] [PATCH V6 0/7] vlan extention - git repository In-Reply-To: <1328015847-20342-1-git-send-email-xiaxia347work@163.com> References: <1328015847-20342-1-git-send-email-xiaxia347work@163.com> Message-ID: <6637b4e0.12b5c.135343fb164.Coremail.xiaxia347work@163.com> the patch could be get from following url: https://gitorious.org/libvirt-cim_develop/libvirt-cim_develop git repository: git://gitorious.org/libvirt-cim_develop/libvirt-cim_develop.git branch vlan_v6 From eblima at linux.vnet.ibm.com Tue Jan 31 17:03:19 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 15:03:19 -0200 Subject: [Libvirt-cim] [PATCH V6 0/7] vlan extention - git repository In-Reply-To: <6637b4e0.12b5c.135343fb164.Coremail.xiaxia347work@163.com> References: <1328015847-20342-1-git-send-email-xiaxia347work@163.com> <6637b4e0.12b5c.135343fb164.Coremail.xiaxia347work@163.com> Message-ID: <4F281ED7.6040600@linux.vnet.ibm.com> On 01/31/2012 12:51 PM, xiaxia347work wrote: > the patch could be get from following url: > https://gitorious.org/libvirt-cim_develop/libvirt-cim_develop > > git repository: > git://gitorious.org/libvirt-cim_develop/libvirt-cim_develop.git > branch vlan_v6 Just a heads up, it was not necessary to create another project on gitorious to host your tree. You can create as many clones as you want on the libvirt-cim project page: http://gitorious.org/libvirt-cim The idea when I created the project in gitorious was to have a common place for developers to host their trees with the work in progress, since write access to libvirt.org repository is restricted to the maintainers of the project. The next step would be to automate the synchronization between libvirt.org and gitorious trees, the same way is done for libvirt (http://gitorious.org/libvirt). Nowadays, I am doing this sync manually, which I think is fine as the 'commit rate' is much lower when compared to libvirt. Best regards, -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From snmishra at linux.vnet.ibm.com Tue Jan 31 17:50:07 2012 From: snmishra at linux.vnet.ibm.com (Sharad Mishra) Date: Tue, 31 Jan 2012 09:50:07 -0800 Subject: [Libvirt-cim] [PATCH 4/4] FilterEntry: Accept protocol id string values In-Reply-To: <1327967871-24219-5-git-send-email-eblima@linux.vnet.ibm.com> References: <1327967871-24219-1-git-send-email-eblima@linux.vnet.ibm.com> <1327967871-24219-5-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1328032207.4193.1267.camel@snmishra-desktop.beaverton.ibm.com> On Mon, 2012-01-30 at 21:57 -0200, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > The HdrProtocolID8021 property expects an unsigned int value, while libvirt > network filters specification allows the corresponding value for this property > (protocolid) to be written as a string (ipv4, ipv6, arp, rarp). > > The corresponding values for the protocolid strings can be found in: > http://www.iana.org/assignments/ethernet-numbers > > Signed-off-by: Eduardo Lima (Etrunko) > --- > src/Virt_FilterEntry.c | 26 ++++++++++++++++++++++++-- > 1 files changed, 24 insertions(+), 2 deletions(-) > > diff --git a/src/Virt_FilterEntry.c b/src/Virt_FilterEntry.c > index 2ff354a..126615b 100644 > --- a/src/Virt_FilterEntry.c > +++ b/src/Virt_FilterEntry.c > @@ -219,6 +219,24 @@ static int convert_action(const char *s) > return action; > } > > +static unsigned long convert_protocol_id(const char *s) > +{ > + enum {NONE = 0, IPV4 = 2048, ARP = 2054, RARP = 32821, IPV6 = 34525} id = NONE; > + > + if (s != NULL) { > + if (STREQC(s, "ipv4")) > + id = IPV4; > + else if (STREQC(s, "arp")) > + id = ARP; > + else if (STREQC(s, "rarp")) > + id = RARP; > + else if (STREQC(s, "ipv6")) > + id = IPV6; > + } > + > + return id; > +} > + > static void convert_mac_rule_to_instance( > struct acl_rule *rule, > CMPIInstance *inst, > @@ -265,8 +283,12 @@ static void convert_mac_rule_to_instance( > (CMPIValue *)&array, CMPI_uint8A); > > if (rule->var.mac.protocol_id != NULL) { > - unsigned long n = strtoul(rule->var.mac.protocol_id, > - NULL, 16); > + unsigned long n = convert_protocol_id(rule->var.mac.protocol_id); > + > + /* Unknown protocolid string. Try converting from hexadecimal value */ > + if (n == 0) > + n = strtoul(rule->var.mac.protocol_id, NULL, 16); > + > CMSetProperty(inst, "HdrProtocolID8021", > (CMPIValue *)&n, CMPI_uint16); Why are we converting to hex if unknown protocol? Can we just use "0" to indicate that its 'unknown'? -Sharad > } From snmishra at linux.vnet.ibm.com Tue Jan 31 18:16:26 2012 From: snmishra at linux.vnet.ibm.com (Sharad Mishra) Date: Tue, 31 Jan 2012 10:16:26 -0800 Subject: [Libvirt-cim] [PATCH 1/4] FilterEntry: Change 'Priority' property type In-Reply-To: <1327967871-24219-2-git-send-email-eblima@linux.vnet.ibm.com> References: <1327967871-24219-1-git-send-email-eblima@linux.vnet.ibm.com> <1327967871-24219-2-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1328033786.4193.1269.camel@snmishra-desktop.beaverton.ibm.com> +1 don't see any issue with this patch. Will apply and test later. -Sharad On Mon, 2012-01-30 at 21:57 -0200, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > According to libvirt network filters specification, since version 0.9.8, > priority values can accept negative values within the range -1000 to 1000. Thus > the FilterEntry property value type went from unsigned int to signed int. > > Signed-off-by: Eduardo Lima (Etrunko) > --- > schema/FilterEntry.mof | 18 +++++++++--------- > src/Virt_FilterEntry.c | 2 +- > 2 files changed, 10 insertions(+), 10 deletions(-) > > diff --git a/schema/FilterEntry.mof b/schema/FilterEntry.mof > index b51150c..f60abae 100644 > --- a/schema/FilterEntry.mof > +++ b/schema/FilterEntry.mof > @@ -30,11 +30,11 @@ class KVM_Hdr8021Filter : CIM_Hdr8021Filter > "the rule will be, instantiated relative to other rules. " > "Rules with lower value will be instantiated and therefore " > "evaluated before rules with higher value. Valid values are " > - "in the range of 0 to 1000. If this attribute is not " > + "in the range of -1000 to 1000. If this attribute is not " > "provided, the value 500 will automatically be assigned."), > - MinValue(0), > + MinValue(-1000), > MaxValue(1000)] > - uint16 Priority = 500; > + sint16 Priority = 500; > }; > > [Provider("cmpi::Virt_FilterEntry")] > @@ -68,11 +68,11 @@ class KVM_IPHeadersFilter : CIM_IPHeadersFilter > "the rule will be, instantiated relative to other rules. " > "Rules with lower value will be instantiated and therefore " > "evaluated before rules with higher value. Valid values are " > - "in the range of 0 to 1000. If this attribute is not " > + "in the range of -1000 to 1000. If this attribute is not " > "provided, the value 500 will automatically be assigned."), > - MinValue(0), > + MinValue(-1000), > MaxValue(1000)] > - uint16 Priority = 500; > + sint16 Priority = 500; > }; > > [Provider("cmpi::Virt_FilterEntry")] > @@ -98,9 +98,9 @@ class KVM_FilterEntry : CIM_FilterEntry > "the rule will be, instantiated relative to other rules. " > "Rules with lower value will be instantiated and therefore " > "evaluated before rules with higher value. Valid values are " > - "in the range of 0 to 1000. If this attribute is not " > + "in the range of -1000 to 1000. If this attribute is not " > "provided, the value 500 will automatically be assigned."), > - MinValue(0), > + MinValue(-1000), > MaxValue(1000)] > - uint16 Priority = 500; > + sint16 Priority = 500; > }; > diff --git a/src/Virt_FilterEntry.c b/src/Virt_FilterEntry.c > index 16b211e..a4fa4cd 100644 > --- a/src/Virt_FilterEntry.c > +++ b/src/Virt_FilterEntry.c > @@ -554,7 +554,7 @@ static CMPIInstance *convert_rule_to_instance( > CMSetProperty(inst, "Direction", (CMPIValue *)&direction, CMPI_uint16); > > priority = convert_priority(rule->priority); > - CMSetProperty(inst, "Priority", (CMPIValue *)&priority, CMPI_uint16); > + CMSetProperty(inst, "Priority", (CMPIValue *)&priority, CMPI_sint16); > > if (convert_f) > convert_f(rule, inst, broker); From snmishra at linux.vnet.ibm.com Tue Jan 31 19:15:32 2012 From: snmishra at linux.vnet.ibm.com (Sharad Mishra) Date: Tue, 31 Jan 2012 11:15:32 -0800 Subject: [Libvirt-cim] [PATCH 3/4] FilterEntry: Update action property In-Reply-To: <1327967871-24219-4-git-send-email-eblima@linux.vnet.ibm.com> References: <1327967871-24219-1-git-send-email-eblima@linux.vnet.ibm.com> <1327967871-24219-4-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1328037332.4193.1271.camel@snmishra-desktop.beaverton.ibm.com> +1 -sharad On Mon, 2012-01-30 at 21:57 -0200, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > According to libvirt network filters specification, new values have been added: > > Since 0.9.0: > - reject > > Since 0.9.7: > - return > - continue > > Signed-off-by: Eduardo Lima (Etrunko) > --- > schema/FilterEntry.mof | 8 ++++---- > src/Virt_FilterEntry.c | 10 ++++++++-- > 2 files changed, 12 insertions(+), 6 deletions(-) > > diff --git a/schema/FilterEntry.mof b/schema/FilterEntry.mof > index f60abae..b5f695f 100644 > --- a/schema/FilterEntry.mof > +++ b/schema/FilterEntry.mof > @@ -6,8 +6,8 @@ class KVM_Hdr8021Filter : CIM_Hdr8021Filter > "This defines whether the action should be to forward or " > "deny traffic meeting the match condition specified in " > "this filter." ), > - ValueMap { "1", "2" }, > - Values { "Permit", "Deny" }] > + ValueMap { "1", "2", "3", "4", "5" }, > + Values { "Permit", "Deny", "Reject", "Return", "Continue" }] > uint16 Action; > > [Description("This defines whether the Filter is used for input, " > @@ -44,8 +44,8 @@ class KVM_IPHeadersFilter : CIM_IPHeadersFilter > "This defines whether the action should be to forward or " > "deny traffic meeting the match condition specified in " > "this filter." ), > - ValueMap { "1", "2" }, > - Values { "Permit", "Deny" }] > + ValueMap { "1", "2", "3", "4", "5" }, > + Values { "Permit", "Deny", "Reject", "Return", "Continue" }] > uint16 Action; > > [Description("This defines whether the Filter is used for input, " > diff --git a/src/Virt_FilterEntry.c b/src/Virt_FilterEntry.c > index c058b5e..2ff354a 100644 > --- a/src/Virt_FilterEntry.c > +++ b/src/Virt_FilterEntry.c > @@ -202,13 +202,19 @@ int convert_priority(const char *s) > > static int convert_action(const char *s) > { > - enum {NONE=0, ACCEPT, DENY} action = NONE; > + enum {NONE=0, ACCEPT, DENY, REJECT, RETURN, CONTINUE} action = NONE; > > if (s != NULL) { > if (STREQC(s, "accept")) > action = ACCEPT; > - else if (STREQC(s, "drop") || STREQC(s, "reject")) > + else if (STREQC(s, "drop")) > action = DENY; > + else if (STREQC(s, "reject")) > + action = REJECT; > + else if (STREQC(s, "return")) > + action = RETURN; > + else if (STREQC(s, "continue")) > + action = CONTINUE; > } > return action; > } From snmishra at linux.vnet.ibm.com Tue Jan 31 19:15:15 2012 From: snmishra at linux.vnet.ibm.com (Sharad Mishra) Date: Tue, 31 Jan 2012 11:15:15 -0800 Subject: [Libvirt-cim] [PATCH 2/4] FilterList: Add 'Priority' property In-Reply-To: <1327967871-24219-3-git-send-email-eblima@linux.vnet.ibm.com> References: <1327967871-24219-1-git-send-email-eblima@linux.vnet.ibm.com> <1327967871-24219-3-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1328037315.4193.1270.camel@snmishra-desktop.beaverton.ibm.com> +1 looks okay -Sharad On Mon, 2012-01-30 at 21:57 -0200, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > According to libvirt network filter specification, since verstion 0.9.8, > filter lists can be assigned priorities. > > Signed-off-by: Eduardo Lima (Etrunko) > --- > libxkutil/acl_parsing.c | 2 ++ > libxkutil/acl_parsing.h | 1 + > schema/FilterList.mof | 9 +++++++++ > src/Makefile.am | 4 ++-- > src/Virt_FilterEntry.c | 11 ++++------- > src/Virt_FilterEntry.h | 6 ++++++ > src/Virt_FilterList.c | 5 ++++- > 7 files changed, 28 insertions(+), 10 deletions(-) > > diff --git a/libxkutil/acl_parsing.c b/libxkutil/acl_parsing.c > index 9c4b4b2..2930928 100644 > --- a/libxkutil/acl_parsing.c > +++ b/libxkutil/acl_parsing.c > @@ -134,6 +134,7 @@ void cleanup_filter(struct acl_filter *filter) > free(filter->uuid); > free(filter->name); > free(filter->chain); > + free(filter->priority); > > for (i = 0; i < filter->rule_ct; i++) > cleanup_rule(filter->rules[i]); > @@ -345,6 +346,7 @@ static int parse_acl_filter(xmlNode *fnode, struct acl_filter *filter) > goto err; > > filter->chain = get_attr_value(fnode, "chain"); > + filter->priority = get_attr_value(fnode, "priority"); > > for (child = fnode->children; child != NULL; child = child->next) { > if (XSTREQ(child->name, "uuid")) { > diff --git a/libxkutil/acl_parsing.h b/libxkutil/acl_parsing.h > index 5b99175..5abcb02 100644 > --- a/libxkutil/acl_parsing.h > +++ b/libxkutil/acl_parsing.h > @@ -148,6 +148,7 @@ struct acl_filter { > char *uuid; > char *name; > char *chain; > + char *priority; > > struct acl_rule **rules; > int rule_ct; > diff --git a/schema/FilterList.mof b/schema/FilterList.mof > index a98c14d..7339db6 100644 > --- a/schema/FilterList.mof > +++ b/schema/FilterList.mof > @@ -1,4 +1,13 @@ > // Copyright IBM Corp. 2011 > class KVM_FilterList : CIM_FilterList > { > + [Description("The priority of the filter controls the order in which " > + "the filter will be, instantiated relative to other filters. " > + "Filters with lower value will be instantiated and therefore " > + "evaluated before rules with higher value. Valid values are " > + "in the range of -1000 to 1000. If this attribute is not " > + "provided, the value 500 will automatically be assigned."), > + MinValue(-1000), > + MaxValue(1000)] > + sint16 Priority = 500; > }; > diff --git a/src/Makefile.am b/src/Makefile.am > index c28dc9a..3f90926 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -255,9 +255,9 @@ libVirt_FilterEntry_la_DEPENDENCIES = libVirt_HostSystem.la > libVirt_FilterEntry_la_SOURCES = Virt_FilterEntry.c > libVirt_FilterEntry_la_LIBADD = -lVirt_HostSystem > > -libVirt_FilterList_la_DEPENDENCIES = libVirt_HostSystem.la > +libVirt_FilterList_la_DEPENDENCIES = libVirt_HostSystem.la libVirt_FilterEntry.la > libVirt_FilterList_la_SOURCES = Virt_FilterList.c > -libVirt_FilterList_la_LIBADD = -lVirt_HostSystem > +libVirt_FilterList_la_LIBADD = -lVirt_HostSystem -lVirt_FilterEntry > > libVirt_EntriesInFilterList_la_DEPENDENCIES = libVirt_FilterEntry.la libVirt_FilterList.la > libVirt_EntriesInFilterList_la_SOURCES = Virt_EntriesInFilterList.c > diff --git a/src/Virt_FilterEntry.c b/src/Virt_FilterEntry.c > index a4fa4cd..c058b5e 100644 > --- a/src/Virt_FilterEntry.c > +++ b/src/Virt_FilterEntry.c > @@ -192,15 +192,12 @@ static int convert_direction(const char *s) > return direction; > } > > -static int convert_priority(const char *s) > +int convert_priority(const char *s) > { > - int priority = 0; > - > - if (s != NULL) { > - priority = atoi(s); > - } > + if (s == NULL) > + return 0; > > - return priority; > + return atoi(s); > } > > static int convert_action(const char *s) > diff --git a/src/Virt_FilterEntry.h b/src/Virt_FilterEntry.h > index 2fe17c4..a30f46d 100644 > --- a/src/Virt_FilterEntry.h > +++ b/src/Virt_FilterEntry.h > @@ -72,6 +72,12 @@ CMPIStatus instance_from_rule( > struct acl_rule *rule, > CMPIInstance **instance); > > +/** > + * Convert a string representing the priority to corresponding integer value > + * > + * @param s A pointer to a string representing the priority > + */ > +int convert_priority(const char *s); > #endif > > /* > diff --git a/src/Virt_FilterList.c b/src/Virt_FilterList.c > index 5b1b6e8..9b5dbae 100644 > --- a/src/Virt_FilterList.c > +++ b/src/Virt_FilterList.c > @@ -31,6 +31,7 @@ > > #include "Virt_FilterList.h" > #include "Virt_HostSystem.h" > +#include "Virt_FilterEntry.h" > > const static CMPIBroker *_BROKER; > > @@ -44,7 +45,7 @@ static CMPIInstance *convert_filter_to_instance( > CMPIInstance *inst = NULL; > const char *sys_name = NULL; > const char *sys_ccname = NULL; > - int direction = 0; > + int direction = 0, priority; > > inst = get_typed_instance(broker, > CLASSNAME(reference), > @@ -77,6 +78,8 @@ static CMPIInstance *convert_filter_to_instance( > CMPI_chars); > CMSetProperty(inst, "Direction", (CMPIValue *)&direction, CMPI_uint16); > > + priority = convert_priority(filter->priority); > + CMSetProperty(inst, "Priority", (CMPIValue *)&priority, CMPI_sint16); > out: > return inst; > } From eblima at linux.vnet.ibm.com Tue Jan 31 19:18:45 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 17:18:45 -0200 Subject: [Libvirt-cim] [PATCH 4/4] FilterEntry: Accept protocol id string values In-Reply-To: <1328032207.4193.1267.camel@snmishra-desktop.beaverton.ibm.com> References: <1327967871-24219-1-git-send-email-eblima@linux.vnet.ibm.com> <1327967871-24219-5-git-send-email-eblima@linux.vnet.ibm.com> <1328032207.4193.1267.camel@snmishra-desktop.beaverton.ibm.com> Message-ID: <4F283E95.7070106@linux.vnet.ibm.com> On 01/31/2012 03:50 PM, Sharad Mishra wrote: > On Mon, 2012-01-30 at 21:57 -0200, Eduardo Lima (Etrunko) wrote: >> From: "Eduardo Lima (Etrunko)" >> >> The HdrProtocolID8021 property expects an unsigned int value, while libvirt >> network filters specification allows the corresponding value for this property >> (protocolid) to be written as a string (ipv4, ipv6, arp, rarp). >> >> The corresponding values for the protocolid strings can be found in: >> http://www.iana.org/assignments/ethernet-numbers >> >> Signed-off-by: Eduardo Lima (Etrunko) >> --- >> src/Virt_FilterEntry.c | 26 ++++++++++++++++++++++++-- >> 1 files changed, 24 insertions(+), 2 deletions(-) >> >> diff --git a/src/Virt_FilterEntry.c b/src/Virt_FilterEntry.c >> index 2ff354a..126615b 100644 >> --- a/src/Virt_FilterEntry.c >> +++ b/src/Virt_FilterEntry.c >> @@ -219,6 +219,24 @@ static int convert_action(const char *s) >> return action; >> } >> >> +static unsigned long convert_protocol_id(const char *s) >> +{ >> + enum {NONE = 0, IPV4 = 2048, ARP = 2054, RARP = 32821, IPV6 = 34525} id = NONE; >> + >> + if (s != NULL) { >> + if (STREQC(s, "ipv4")) >> + id = IPV4; >> + else if (STREQC(s, "arp")) >> + id = ARP; >> + else if (STREQC(s, "rarp")) >> + id = RARP; >> + else if (STREQC(s, "ipv6")) >> + id = IPV6; >> + } >> + >> + return id; >> +} >> + >> static void convert_mac_rule_to_instance( >> struct acl_rule *rule, >> CMPIInstance *inst, >> @@ -265,8 +283,12 @@ static void convert_mac_rule_to_instance( >> (CMPIValue *)&array, CMPI_uint8A); >> >> if (rule->var.mac.protocol_id != NULL) { >> - unsigned long n = strtoul(rule->var.mac.protocol_id, >> - NULL, 16); >> + unsigned long n = convert_protocol_id(rule->var.mac.protocol_id); >> + >> + /* Unknown protocolid string. Try converting from hexadecimal value */ >> + if (n == 0) >> + n = strtoul(rule->var.mac.protocol_id, NULL, 16); >> + >> CMSetProperty(inst, "HdrProtocolID8021", >> (CMPIValue *)&n, CMPI_uint16); > > Why are we converting to hex if unknown protocol? Can we just use "0" > to indicate that its 'unknown'? The problem is that this value can be either a pre-define string (ipv4, ipv6, arp, rarp)or an hexadecimal value in string form. The idea here is first try to match the value with one of those pre defined values calling convert_protocol_id() and if it fails, we try converting the string to hexadecimal value. In case it fails it will return 0. Makes sense? -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Tue Jan 31 20:25:08 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 18:25:08 -0200 Subject: [Libvirt-cim] [PATCH v3 0/2] Implementation of a linked list helper In-Reply-To: <1327085304-23780-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1327085304-23780-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F284E24.4010603@linux.vnet.ibm.com> On 01/20/2012 04:48 PM, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > This series provides a generic linked list implementation for libxkutil that is > based on the one originally developed for the libvirt domain events support > recently integrated upstream. > > As test case I ported the ComputerSystemIndication provider code to use this > list implementation. In the near future it will be also used by the event loop > that I am currently working on to allow systems with libvirt older than 0.9.0 > to make use of the same feature. > > Other possible use cases would be to port the code of libxkutil/*_parsing* to > also use the list implementation instead of static arrays. > I've found some issues with this implementation which are already fixed. Please ignore this series. I will be sending the v4 in a few moments. Best regards, -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From snmishra at linux.vnet.ibm.com Tue Jan 31 21:00:42 2012 From: snmishra at linux.vnet.ibm.com (Sharad Mishra) Date: Tue, 31 Jan 2012 13:00:42 -0800 Subject: [Libvirt-cim] [PATCH 3/4] FilterEntry: Update action property In-Reply-To: <1327967871-24219-4-git-send-email-eblima@linux.vnet.ibm.com> References: <1327967871-24219-1-git-send-email-eblima@linux.vnet.ibm.com> <1327967871-24219-4-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1328043642.4193.1272.camel@snmishra-desktop.beaverton.ibm.com> seeing following issue now - FilterList - 01_enum.py: PASS -------------------------------------------------------------------- FilterList - 02_assoc.py: FAIL ERROR - CIMError : (1, u'CIM_ERR_FAILED: Failed to load the Provider Manager for interface type "CMPI" from library "".') Traceback (most recent call last): File "/tmp/remove_me/cimtest/suites/libvirt-cim/lib/XenKvmLib/const.py", line 141, in do_try rc = f() File "02_assoc.py", line 50, in main cim_filters = _test.cim_entries_in_filter_lists() File "/tmp/remove_me/cimtest/suites/libvirt-cim/cimtest/FilterList/helper.py", line 269, in cim_entries_in_filter_lists l.extend(self.Associators(n, result_class="CIM_FilterEntryBase")) File "/tmp/remove_me/cimtest/suites/libvirt-cim/cimtest/FilterList/helper.py", line 88, in Associators return self.wbem.Associators(typed_class, **kargs) File "/usr/lib/python2.6/site-packages/pywbem/cim_operations.py", line 696, in Associators **params) File "/usr/lib/python2.6/site-packages/pywbem/cim_operations.py", line 219, in imethodcall raise CIMError(code, tt[1]['DESCRIPTION']) CIMError: (1, u'CIM_ERR_FAILED: Failed to load the Provider Manager for interface type "CMPI" from library "".') ERROR - None -------------------------------------------------------------------- FilterList - 03_create.py: PASS -Sharad On Mon, 2012-01-30 at 21:57 -0200, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > According to libvirt network filters specification, new values have been added: > > Since 0.9.0: > - reject > > Since 0.9.7: > - return > - continue > > Signed-off-by: Eduardo Lima (Etrunko) > --- > schema/FilterEntry.mof | 8 ++++---- > src/Virt_FilterEntry.c | 10 ++++++++-- > 2 files changed, 12 insertions(+), 6 deletions(-) > > diff --git a/schema/FilterEntry.mof b/schema/FilterEntry.mof > index f60abae..b5f695f 100644 > --- a/schema/FilterEntry.mof > +++ b/schema/FilterEntry.mof > @@ -6,8 +6,8 @@ class KVM_Hdr8021Filter : CIM_Hdr8021Filter > "This defines whether the action should be to forward or " > "deny traffic meeting the match condition specified in " > "this filter." ), > - ValueMap { "1", "2" }, > - Values { "Permit", "Deny" }] > + ValueMap { "1", "2", "3", "4", "5" }, > + Values { "Permit", "Deny", "Reject", "Return", "Continue" }] > uint16 Action; > > [Description("This defines whether the Filter is used for input, " > @@ -44,8 +44,8 @@ class KVM_IPHeadersFilter : CIM_IPHeadersFilter > "This defines whether the action should be to forward or " > "deny traffic meeting the match condition specified in " > "this filter." ), > - ValueMap { "1", "2" }, > - Values { "Permit", "Deny" }] > + ValueMap { "1", "2", "3", "4", "5" }, > + Values { "Permit", "Deny", "Reject", "Return", "Continue" }] > uint16 Action; > > [Description("This defines whether the Filter is used for input, " > diff --git a/src/Virt_FilterEntry.c b/src/Virt_FilterEntry.c > index c058b5e..2ff354a 100644 > --- a/src/Virt_FilterEntry.c > +++ b/src/Virt_FilterEntry.c > @@ -202,13 +202,19 @@ int convert_priority(const char *s) > > static int convert_action(const char *s) > { > - enum {NONE=0, ACCEPT, DENY} action = NONE; > + enum {NONE=0, ACCEPT, DENY, REJECT, RETURN, CONTINUE} action = NONE; > > if (s != NULL) { > if (STREQC(s, "accept")) > action = ACCEPT; > - else if (STREQC(s, "drop") || STREQC(s, "reject")) > + else if (STREQC(s, "drop")) > action = DENY; > + else if (STREQC(s, "reject")) > + action = REJECT; > + else if (STREQC(s, "return")) > + action = RETURN; > + else if (STREQC(s, "continue")) > + action = CONTINUE; > } > return action; > } From eblima at linux.vnet.ibm.com Tue Jan 31 21:06:23 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:06:23 -0200 Subject: [Libvirt-cim] [PATCH 2/3] CSI: Use list helper implementation In-Reply-To: <1328043984-12742-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1328043984-12742-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1328043984-12742-3-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- src/Virt_ComputerSystemIndication.c | 95 ++++++++++------------------------- 1 files changed, 26 insertions(+), 69 deletions(-) diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c index 6ef2ddc..712e12c 100644 --- a/src/Virt_ComputerSystemIndication.c +++ b/src/Virt_ComputerSystemIndication.c @@ -19,6 +19,10 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #include #include @@ -34,11 +38,11 @@ #include #include -#include #include -#include -#include "config.h" +#include +#include +#include #include "Virt_ComputerSystem.h" #include "Virt_ComputerSystemIndication.h" @@ -64,8 +68,6 @@ struct _csi_dom_xml_t { char uuid[VIR_UUID_STRING_BUFLEN]; char *name; char *xml; - csi_dom_xml_t *next; - csi_dom_xml_t *prev; }; typedef struct _csi_thread_data_t csi_thread_data_t; @@ -73,7 +75,7 @@ struct _csi_thread_data_t { CMPI_THREAD_TYPE id; int active_filters; int dom_count; - csi_dom_xml_t *dom_list; + list_t *dom_list; struct ind_args *args; }; @@ -83,15 +85,24 @@ static bool lifecycle_enabled = false; static csi_thread_data_t csi_thread_data[CSI_NUM_PLATFORMS] = {{0}, {0}, {0}}; /* - * Domain list manipulation + * Domain manipulation */ -static void csi_dom_xml_free(csi_dom_xml_t *dom) +static void csi_dom_xml_free(void *data) { + csi_dom_xml_t *dom = (csi_dom_xml_t *) data; free(dom->xml); free(dom->name); free(dom); } +static int csi_dom_xml_cmp(void *data, void *cmp_cb_data) +{ + csi_dom_xml_t *dom = (csi_dom_xml_t *) data; + const char *uuid = (const char *) cmp_cb_data; + + return strcmp(dom->uuid, uuid); +} + static int csi_dom_xml_set(csi_dom_xml_t *dom, virDomainPtr dom_ptr, CMPIStatus *s) { const char *name; @@ -150,65 +161,10 @@ static csi_dom_xml_t *csi_dom_xml_new(virDomainPtr dom_ptr, CMPIStatus *s) static void csi_thread_dom_list_append(csi_thread_data_t *thread, csi_dom_xml_t *dom) { - /* empty list */ - if (thread->dom_list == NULL) { - dom->next = dom->prev = dom; - thread->dom_list = dom; - goto end; - } - - dom->next = thread->dom_list; - dom->prev = thread->dom_list->prev; - - thread->dom_list->prev->next = dom; - thread->dom_list->prev = dom; - - end: - thread->dom_count += 1; -} - -static csi_dom_xml_t *csi_thread_dom_list_find(csi_thread_data_t *thread, - const char *uuid) -{ - csi_dom_xml_t *dom; - if (thread->dom_list == NULL) - return NULL; - - dom = thread->dom_list; - - do { - if (STREQ(dom->uuid, uuid)) - return dom; - - dom = dom->next; - } while (dom != thread->dom_list); + thread->dom_list = list_new(csi_dom_xml_free, csi_dom_xml_cmp); - return NULL; -} - -static void csi_thread_dom_list_remove(csi_thread_data_t *thread, - csi_dom_xml_t *dom) -{ - if (dom->next == dom) { /* Only one node */ - thread->dom_list = NULL; - } else { - if (thread->dom_list == dom) /* First node */ - thread->dom_list = dom->next; - - dom->prev->next = dom->next; - dom->next->prev = dom->prev; - } - - thread->dom_count -= 1; - - csi_dom_xml_free(dom); -} - -static void csi_thread_dom_list_free(csi_thread_data_t *thread) -{ - while(thread->dom_list != NULL) - csi_thread_dom_list_remove(thread, thread->dom_list); + list_append(thread->dom_list, dom); } static void csi_free_thread_data(void *data) @@ -218,7 +174,8 @@ static void csi_free_thread_data(void *data) if (data == NULL) return; - csi_thread_dom_list_free(thread); + list_free(thread->dom_list); + thread->dom_list = NULL; stdi_free_ind_args(&thread->args); } @@ -512,7 +469,7 @@ static int update_domain_list(virConnectPtr conn, csi_thread_data_t *thread) CMPIStatus s = {CMPI_RC_OK, NULL}; int i, count; - csi_thread_dom_list_free(thread); + list_free(thread->dom_list); count = get_domain_list(conn, &dom_ptr_list); @@ -574,7 +531,7 @@ static int csi_domain_event_cb(virConnectPtr conn, if (cs_event != CS_CREATED) { char uuid[VIR_UUID_STRING_BUFLEN] = {0}; virDomainGetUUIDString(dom, &uuid[0]); - dom_xml = csi_thread_dom_list_find(thread, uuid); + dom_xml = list_find(thread->dom_list, uuid); } if (dom_xml == NULL) { @@ -595,7 +552,7 @@ static int csi_domain_event_cb(virConnectPtr conn, } } else if (event == VIR_DOMAIN_EVENT_DEFINED && detail == VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) { - csi_thread_dom_list_remove(thread, dom_xml); + list_remove(thread->dom_list, dom_xml); } end: -- 1.7.7.6 From eblima at linux.vnet.ibm.com Tue Jan 31 21:06:24 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:06:24 -0200 Subject: [Libvirt-cim] [PATCH 3/3] ACL: Use linked list helper for filter refs In-Reply-To: <1328043984-12742-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1328043984-12742-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1328043984-12742-4-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/acl_parsing.c | 58 +++++++++------------------------- libxkutil/acl_parsing.h | 5 ++- libxkutil/xmlgen.c | 30 +++++++++++++---- src/Virt_NestedFilterList.c | 73 +++++++++++++++++++++++------------------- 4 files changed, 81 insertions(+), 85 deletions(-) diff --git a/libxkutil/acl_parsing.c b/libxkutil/acl_parsing.c index 9c4b4b2..f7efcfc 100644 --- a/libxkutil/acl_parsing.c +++ b/libxkutil/acl_parsing.c @@ -141,11 +141,7 @@ void cleanup_filter(struct acl_filter *filter) free(filter->rules); filter->rule_ct = 0; - for (i = 0; i < filter->ref_ct; i++) - free(filter->refs[i]); - - free(filter->refs); - filter->ref_ct = 0; + list_free(filter->refs); } void cleanup_filters(struct acl_filter **filters, int count) @@ -610,58 +606,34 @@ int append_filter_rule(struct acl_filter *filter, struct acl_rule *rule) return 1; } -int append_filter_ref(struct acl_filter *filter, char *name) -{ - int i; - char **old_refs = NULL; - - if ((filter == NULL) || (name == NULL)) - return 0; - - for (i = 0; i < filter->ref_ct; i++) - if (STREQC(filter->refs[i], name)) - return 0; /* already exists */ - - old_refs = filter->refs; - filter->refs = malloc((filter->ref_ct + 1) * sizeof(char *)); +static int filter_ref_cmp(void *list_data, void *user_data) +{ + return strcmp((const char *)list_data, (const char *) user_data); +} - if (filter->refs == NULL) { - CU_DEBUG("Failed to allocate memory for new ref"); - filter->refs = old_refs; +int append_filter_ref(struct acl_filter *filter, char *name) +{ + if (filter == NULL || name == NULL) return 0; - } - memcpy(filter->refs, old_refs, filter->ref_ct * sizeof(char *)); + if (filter->refs == NULL) + filter->refs = list_new(free, filter_ref_cmp); - filter->refs[filter->ref_ct] = name; - filter->ref_ct++; + if (list_find(filter->refs, name) != NULL) + return 0; /* already exists */ - free(old_refs); + list_append(filter->refs, name); return 1; } int remove_filter_ref(struct acl_filter *filter, const char *name) { - int i; - char **old_refs = NULL; - - if ((filter == NULL) || (name == NULL)) + if (filter == NULL || filter->refs == NULL || name == NULL) return 0; - /* TODO: called infrequently, but needs optimization */ - old_refs = filter->refs; - filter->ref_ct = 0; - - for (i = 0; i < filter->ref_ct; i++) { - if (STREQC(old_refs[i], name)) { - free(old_refs[i]); - } - else if(append_filter_ref(filter, old_refs[i]) == 0) { - return 0; - } - } + list_remove(filter->refs, (void *) name); return 1; } diff --git a/libxkutil/acl_parsing.h b/libxkutil/acl_parsing.h index 5b99175..e49f384 100644 --- a/libxkutil/acl_parsing.h +++ b/libxkutil/acl_parsing.h @@ -26,6 +26,8 @@ #include #include +#include "list_util.h" + struct acl_mac_rule { char *srcmacaddr; char *srcmacmask; @@ -152,8 +154,7 @@ struct acl_filter { struct acl_rule **rules; int rule_ct; - char **refs; - int ref_ct; + list_t *refs; }; void cleanup_rule(struct acl_rule *rule); diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index 9a2ada9..5c16ebe 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -28,6 +28,7 @@ #include #include "xmlgen.h" +#include "list_util.h" #ifndef TEST #include "misc_util.h" @@ -1467,12 +1468,31 @@ char *res_to_xml(struct virt_pool_res *res) { return xml; } +static bool filter_ref_foreach(void *list_data, void *user_data) +{ + char *filter = (char *) list_data; + xmlNodePtr root = (xmlNodePtr) user_data; + xmlNodePtr tmp = NULL; + + tmp = xmlNewChild(root, NULL, BAD_CAST "filterref", NULL); + if (tmp == NULL) { + CU_DEBUG("Error creating filterref node"); + return false; + } + + if (xmlNewProp(tmp, BAD_CAST "filter", BAD_CAST list_data) == NULL) { + CU_DEBUG("Error adding filter attribute '%s'", filter); + return false; + } + + return true; +} + char *filter_to_xml(struct acl_filter *filter) { char *xml = NULL; xmlNodePtr root = NULL; xmlNodePtr tmp = NULL; - int i; root = xmlNewNode(NULL, BAD_CAST "filter"); if (root == NULL) @@ -1494,12 +1514,8 @@ char *filter_to_xml(struct acl_filter *filter) goto out; } - for (i = 0; i < filter->ref_ct; i++) { - tmp = xmlNewChild(root, NULL, BAD_CAST "filterref", NULL); - if (xmlNewProp(tmp, BAD_CAST "filter", - BAD_CAST filter->refs[i]) == NULL) - goto out; - } + if (!list_foreach(filter->refs, filter_ref_foreach, (void *) root)) + goto out; xml = tree_to_xml(root); diff --git a/src/Virt_NestedFilterList.c b/src/Virt_NestedFilterList.c index 81c4408..a8565d6 100644 --- a/src/Virt_NestedFilterList.c +++ b/src/Virt_NestedFilterList.c @@ -34,6 +34,7 @@ #include "acl_parsing.h" #include "misc_util.h" +#include "list_util.h" #include "Virt_FilterList.h" static const CMPIBroker *_BROKER; @@ -120,7 +121,7 @@ static CMPIStatus parent_to_child( CMPIInstance *instance = NULL; const char * name = NULL; virConnectPtr conn = NULL; - int i; + list_node_t *head, *node; CU_DEBUG("Reference = %s", REF2STR(reference)); @@ -139,29 +140,39 @@ static CMPIStatus parent_to_child( if (parent_filter == NULL) goto out; - for (i = 0; i < parent_filter->ref_ct; i++) { - get_filter_by_name(conn, parent_filter->refs[i], - &child_filter); - if (child_filter == NULL) - continue; - - CU_DEBUG("Processing %s,", child_filter->name); - - s = instance_from_filter(_BROKER, - info->context, - reference, - child_filter, - &instance); + /* Walk refs list */ + if (parent_filter->refs == NULL) + goto end; + + head = node = list_first_node(parent_filter->refs); + if (head == NULL) + goto end; + + do { + name = (const char *) list_node_data_get(node); + get_filter_by_name(conn, name, &child_filter); + if (child_filter != NULL) { + CU_DEBUG("Processing %s,", child_filter->name); + + s = instance_from_filter(_BROKER, + info->context, + reference, + child_filter, + &instance); + + if (instance != NULL) { + CU_DEBUG("Adding instance to inst_list"); + inst_list_add(list, instance); + } - if (instance != NULL) { - CU_DEBUG("Adding instance to inst_list"); - inst_list_add(list, instance); + cleanup_filters(&child_filter, 1); } - cleanup_filters(&child_filter, 1); instance = NULL; - } + node = list_node_next_node(node); + } while (node != head); + end: cleanup_filters(&parent_filter, 1); out: @@ -183,7 +194,7 @@ static CMPIStatus child_to_parent( CMPIInstance *instance = NULL; const char *name = NULL; virConnectPtr conn = NULL; - int count, i, j; + int count, i; CU_DEBUG("Reference = %s", REF2STR(reference)); @@ -206,24 +217,20 @@ static CMPIStatus child_to_parent( /* return any filter that has name in refs */ for (i = 0; i < count; i++) { - for (j = 0; j < _list[i].ref_ct; j++) { - if (STREQC(name, _list[i].refs[j])) { - CU_DEBUG("Processing %s,", _list[i].name); + if (list_find_node(_list[i].refs, (void *) name) != NULL) { + CU_DEBUG("Processing %s,", _list[i].name); - s = instance_from_filter(_BROKER, - info->context, - reference, - &_list[i], - &instance); - - if (instance != NULL) - inst_list_add(list, instance); + s = instance_from_filter(_BROKER, + info->context, + reference, + &_list[i], + &instance); + if (instance != NULL) { + inst_list_add(list, instance); instance = NULL; } - } - } cleanup_filters(&_list, count); -- 1.7.7.6 From eblima at linux.vnet.ibm.com Tue Jan 31 21:06:22 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:06:22 -0200 Subject: [Libvirt-cim] [PATCH 1/3] libxkutil: Linked list helper In-Reply-To: <1328043984-12742-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1328043984-12742-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1328043984-12742-2-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/Makefile.am | 51 +++++++--- libxkutil/list_util.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++++ libxkutil/list_util.h | 73 ++++++++++++++ 3 files changed, 364 insertions(+), 14 deletions(-) create mode 100644 libxkutil/list_util.c create mode 100644 libxkutil/list_util.h diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am index f1adc03..8d436ad 100644 --- a/libxkutil/Makefile.am +++ b/libxkutil/Makefile.am @@ -1,21 +1,44 @@ # Copyright IBM Corp. 2007 +AM_CFLAGS = \ + $(CFLAGS_STRICT) \ + -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" -AM_CFLAGS = $(CFLAGS_STRICT) \ - -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" +noinst_HEADERS = \ + cs_util.h \ + misc_util.h \ + device_parsing.h \ + xmlgen.h \ + infostore.h \ + pool_parsing.h \ + acl_parsing.h \ + list_util.h -noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ - pool_parsing.h acl_parsing.h +lib_LTLIBRARIES = \ + libxkutil.la -lib_LTLIBRARIES = libxkutil.la +libxkutil_la_SOURCES = \ + cs_util_instance.c \ + misc_util.c \ + device_parsing.c \ + xmlgen.c \ + infostore.c \ + pool_parsing.c \ + acl_parsing.c \ + list_util.c -libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ - xmlgen.c infostore.c pool_parsing.c acl_parsing.c -libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ -libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ - @LIBUUID_LIBS@ +libxkutil_la_LDFLAGS = \ + -version-info @VERSION_INFO@ -noinst_PROGRAMS = xml_parse_test +libxkutil_la_LIBADD = \ + @LIBVIRT_LIBS@ \ + @LIBUUID_LIBS@ -xml_parse_test_SOURCES = xml_parse_test.c -xml_parse_test_LDADD = libxkutil.la \ - @LIBVIRT_LIBS@ +noinst_PROGRAMS = \ + xml_parse_test + +xml_parse_test_SOURCES = \ + xml_parse_test.c + +xml_parse_test_LDADD = \ + libxkutil.la \ + @LIBVIRT_LIBS@ diff --git a/libxkutil/list_util.c b/libxkutil/list_util.c new file mode 100644 index 0000000..dc3629f --- /dev/null +++ b/libxkutil/list_util.c @@ -0,0 +1,254 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Eduardo Lima (Etrunko) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "list_util.h" + +struct _list_node_t { + list_node_t *prev; + list_node_t *next; + void *data; +}; + +struct _list_t { + unsigned int count; + list_node_t *head; + list_data_free_cb free_cb; + list_data_cmp_cb cmp_cb; +}; + +list_t *list_new(list_data_free_cb free_cb, list_data_cmp_cb cmp_cb) +{ + list_t *l = calloc(1, sizeof(*l)); + if (l == NULL) + return NULL; + + l->free_cb = free_cb; + l->cmp_cb = cmp_cb; + return l; +} + +void list_free(list_t *list) +{ + list_node_t *n, *next; + + if (list == NULL || list->head == NULL) + return; + + n = list->head; + + do { + if (list->free_cb) + list->free_cb(n->data); + + next = n->next; + free(n); + n = next; + } while (n != list->head); + + free(list); +} + +void list_append(list_t *list, void *data) +{ + list_node_t *n; + + if (list == NULL) + return; + + n = calloc(1, sizeof(*n)); + + if (n == NULL) + return; + + n->data = data; + + if (list->head == NULL) { /* empty list */ + n->next = n->prev = n; + list->head = n; + goto end; + } + + n->next = list->head; + n->prev = list->head->prev; + + list->head->prev->next = n; + list->head->prev = n; + + end: + list->count += 1; +} + +void list_prepend(list_t *list, void *data) +{ + list_append(list, data); + list->head = list->head->prev; +} + +void *list_find(list_t *list, void *user_data) +{ + list_node_t *n = list_find_node(list, user_data); + return list_node_data_get(n); +} + +list_node_t *list_find_node(list_t *list, void *user_data) +{ + list_node_t *n; + + if (list == NULL || list->head == NULL || list->cmp_cb == NULL) + return NULL; + + n = list->head; + do { + if (list->cmp_cb(n->data, user_data) == 0) + return n; + + n = n->next; + } while (n != list->head); + + return NULL; +} + +void list_remove(list_t *list, void *data) +{ + list_node_t *n = list_find_node(list, data); + list_remove_node(list, n); +} + +void list_remove_node(list_t *list, list_node_t *node) +{ + if (list == NULL || list->head == NULL || node == NULL) + return; + + if (node->next == node) { /* only 1 item */ + list->head = NULL; + } else { + if (node == list->head) /* first node */ + list->head = node->next; + + node->prev->next = node->next; + node->next->prev = node->prev; + } + + if (list->free_cb) + list->free_cb(node->data); + + free(node); + list->count -= 1; +} + +bool list_foreach(list_t *list, list_foreach_cb cb, void *user_data) +{ + list_node_t *node; + + if (list == NULL || list->head == NULL) + return true; /* nothing to do */ + + node = list->head; + do { + if (cb(node->data, user_data) == false) + return false; + + node = node->next; + } while (node != list->head); + + return true; +} + +unsigned int list_count(list_t *list) +{ + if (list == NULL) + return 0; + + return list->count; +} + +void *list_node_data_get(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->data; +} + +void list_node_data_set(list_node_t *node, void *data) +{ + if (node == NULL) + return; + + node->data = data; +} + +void *list_first(list_t *list) +{ + return list_node_data_get(list->head); +} + +list_node_t *list_first_node(list_t *list) +{ + if (list == NULL) + return NULL; + + return list->head; +} + +void *list_last(list_t *list) +{ + return list_node_data_get(list_last_node(list)); +} + +list_node_t *list_last_node(list_t *list) +{ + if (list == NULL) + return NULL; + + return list->head->prev; +} + +void *list_node_next(list_node_t *node) +{ + return list_node_data_get(list_node_next_node(node)); +} + +list_node_t *list_node_next_node(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->next; +} + +void *list_node_prev(list_node_t *node) +{ + return list_node_data_get(list_node_prev_node(node)); +} + +list_node_t *list_node_prev_node(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->prev; +} diff --git a/libxkutil/list_util.h b/libxkutil/list_util.h new file mode 100644 index 0000000..1809c2e --- /dev/null +++ b/libxkutil/list_util.h @@ -0,0 +1,73 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Eduardo Lima (Etrunko) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LIST_UTIL_H +#define __LIST_UTIL_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*list_data_free_cb)(void *data); +typedef int (*list_data_cmp_cb)(void *list_data, void *user_data); +typedef bool (*list_foreach_cb)(void *list_data, void *user_data); + +typedef struct _list_node_t list_node_t; +typedef struct _list_t list_t; + +list_t *list_new(list_data_free_cb free_cb, list_data_cmp_cb cmp_cb); +void list_free(list_t *list); + +void list_append(list_t *list, void *data); +void list_prepend(list_t *list, void *data); + +void *list_find(list_t *list, void *user_data); +list_node_t *list_find_node(list_t *list, void *user_data); + +void list_remove(list_t *list, void *data); +void list_remove_node(list_t *list, list_node_t *node); + +bool list_foreach(list_t *list, list_foreach_cb cb, void *user_data); + +inline unsigned int list_count(list_t *list); + +inline void *list_node_data_get(list_node_t *node); +inline void list_node_data_set(list_node_t *node, void *data); + +inline void *list_first(list_t *list); +inline list_node_t *list_first_node(list_t *list); + +inline void *list_last(list_t *list); +inline list_node_t *list_last_node(list_t *list); + +inline void *list_node_next(list_node_t *node); +inline list_node_t *list_node_next_node(list_node_t *node); + +inline void *list_node_prev(list_node_t *node); +inline list_node_t *list_node_prev_node(list_node_t *node); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __LIST_UTIL_H */ -- 1.7.7.6 From eblima at linux.vnet.ibm.com Tue Jan 31 21:06:21 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:06:21 -0200 Subject: [Libvirt-cim] [PATCH v4 0/3] Implementation of a linked list helper Message-ID: <1328043984-12742-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" This series provides a generic linked list implementation for libxkutil that is based on the one originally developed for the libvirt domain events support recently integrated upstream. As test case I ported the ComputerSystemIndication provider code to use this list implementation. In the near future it will be also used by the event loop that I am currently working on to allow systems with libvirt older than 0.9.0 to make use of the same feature. Other possible use cases would be to port the code of libxkutil/*_parsing* to also use the list implementation instead of static arrays. Changes from v3: - Fix crashes in list_free(), list_first_node() and list_count() - Include patch that ports the acl filter ref code to use the linked list implementation Changes from v2: - Make list struct private Changes from v1: - Fix version iformation in Makefile.am Eduardo Lima (Etrunko) (3): libxkutil: Linked list helper CSI: Use list helper implementation ACL: Use linked list helper for filter refs libxkutil/Makefile.am | 51 +++++-- libxkutil/acl_parsing.c | 58 ++------ libxkutil/acl_parsing.h | 5 +- libxkutil/list_util.c | 254 +++++++++++++++++++++++++++++++++++ libxkutil/list_util.h | 73 ++++++++++ libxkutil/xmlgen.c | 30 +++- src/Virt_ComputerSystemIndication.c | 95 ++++---------- src/Virt_NestedFilterList.c | 73 ++++++----- 8 files changed, 471 insertions(+), 168 deletions(-) create mode 100644 libxkutil/list_util.c create mode 100644 libxkutil/list_util.h -- 1.7.7.6 From eblima at linux.vnet.ibm.com Tue Jan 31 21:22:25 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:22:25 -0200 Subject: [Libvirt-cim] [PATCH v4] Fix AppliedFilterList creation and deletion In-Reply-To: <1327608066-21678-1-git-send-email-cvincent@linux.vnet.ibm.com> References: <1327608066-21678-1-git-send-email-cvincent@linux.vnet.ibm.com> Message-ID: <4F285B91.5010101@linux.vnet.ibm.com> On 01/26/2012 06:01 PM, Chip Vincent wrote: > From: Chip Vincent > > Fixes many small issues with the current AppliedFilterList provider. > > 1) Fix Create to properly return a complete object path and fix Delete to > properly parse that path. > > 2) Persist applied filer rules. Since it's not possible to dyanmically update > a single device, I've changed the code to modify and re-define the VM to > essentially add/remove ACL filter associations. > > I also updated the code to minimize domain/device parsing overhead. For > some strange reason, our internal APIs sometimes take a virDomainPtr and > other times a struct domain * forcing providers who work with domains > *and* devices to parse everything twice. Until the internal APIs are > cleaned up, I simply parse everything once and then fetch the device > manually from the struct domain *. > > 3) Add VIR_DOMAIN_XML_INACTIVE to virDomainGetXML(). By default, libvirt only > returns the XML of the running domain. We need to fetch the *stored* XML > that will be used for the next boot so that all changes made while the VM > is running are preserved. > > Changes from v3: > - Fix NestedFilterList DeleteInstance > - Fix remove_filter_ref() in acl_parsing.c (intend to refactor in > future patch) > > Changes from v2: > - Return the correct reference in NestedFilterList > > Changes from v1: > - Fix leak and other comments > - Fix all cases virDomainGetXML() > - Fix NestedFilterList Create/Delete instance > > Signed-off-by: Chip Vincent > --- > libxkutil/acl_parsing.c | 1 + > libxkutil/device_parsing.c | 6 ++- > src/Virt_AppliedFilterList.c | 97 +++++++++++++++++++---------------- > src/Virt_ComputerSystem.c | 3 +- > src/Virt_ComputerSystemIndication.c | 3 +- > src/Virt_FilterList.c | 5 ++- > src/Virt_NestedFilterList.c | 19 +++++-- > src/Virt_VSMigrationService.c | 3 +- > 8 files changed, 82 insertions(+), 55 deletions(-) > > diff --git a/libxkutil/acl_parsing.c b/libxkutil/acl_parsing.c > index 5b6d7bb..9c4b4b2 100644 > --- a/libxkutil/acl_parsing.c > +++ b/libxkutil/acl_parsing.c > @@ -652,6 +652,7 @@ int remove_filter_ref(struct acl_filter *filter, const char *name) > > /* TODO: called infrequently, but needs optimization */ > old_refs = filter->refs; > + filter->ref_ct = 0; I know it is a bit too late, since the code has already been pushed. Taking a closer look now, I find this line avoids the crash we were having in the deletion of the NestedFilterList instance, but in the end it will cause filter->refs to leak. I tried to understand the code and it looks too much complex for the purpose of only removing a string of an array. Taking this into account, I took the next step and ported the ACL code to use the linked list implementation. I have just updated the linked list patch series and sent v4 for review. Please take a look. We should either use this new patch or fix this code properly. Best regards, -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Tue Jan 31 21:34:55 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:34:55 -0200 Subject: [Libvirt-cim] [PATCH 3/3] ACL: Use linked list helper for filter refs In-Reply-To: <1328043984-12742-4-git-send-email-eblima@linux.vnet.ibm.com> References: <1328043984-12742-1-git-send-email-eblima@linux.vnet.ibm.com> <1328043984-12742-4-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F285E7F.1090906@linux.vnet.ibm.com> On 01/31/2012 07:06 PM, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > Signed-off-by: Eduardo Lima (Etrunko) > --- > libxkutil/acl_parsing.c | 58 +++++++++------------------------- > libxkutil/acl_parsing.h | 5 ++- > libxkutil/xmlgen.c | 30 +++++++++++++---- > src/Virt_NestedFilterList.c | 73 +++++++++++++++++++++++------------------- > 4 files changed, 81 insertions(+), 85 deletions(-) > > diff --git a/libxkutil/acl_parsing.c b/libxkutil/acl_parsing.c > index 9c4b4b2..f7efcfc 100644 > --- a/libxkutil/acl_parsing.c > +++ b/libxkutil/acl_parsing.c > @@ -141,11 +141,7 @@ void cleanup_filter(struct acl_filter *filter) > free(filter->rules); > filter->rule_ct = 0; > > - for (i = 0; i < filter->ref_ct; i++) > - free(filter->refs[i]); > - > - free(filter->refs); > - filter->ref_ct = 0; > + list_free(filter->refs); > } > > void cleanup_filters(struct acl_filter **filters, int count) > @@ -610,58 +606,34 @@ int append_filter_rule(struct acl_filter *filter, struct acl_rule *rule) > return 1; > } > > -int append_filter_ref(struct acl_filter *filter, char *name) > -{ > - int i; > - char **old_refs = NULL; > - > - if ((filter == NULL) || (name == NULL)) > - return 0; > - > - for (i = 0; i < filter->ref_ct; i++) > - if (STREQC(filter->refs[i], name)) > - return 0; /* already exists */ > - > - old_refs = filter->refs; > > - filter->refs = malloc((filter->ref_ct + 1) * sizeof(char *)); > +static int filter_ref_cmp(void *list_data, void *user_data) > +{ > + return strcmp((const char *)list_data, (const char *) user_data); > +} > > - if (filter->refs == NULL) { > - CU_DEBUG("Failed to allocate memory for new ref"); > - filter->refs = old_refs; > +int append_filter_ref(struct acl_filter *filter, char *name) > +{ > + if (filter == NULL || name == NULL) > return 0; > - } > > - memcpy(filter->refs, old_refs, filter->ref_ct * sizeof(char *)); > + if (filter->refs == NULL) > + filter->refs = list_new(free, filter_ref_cmp); > > - filter->refs[filter->ref_ct] = name; > - filter->ref_ct++; > + if (list_find(filter->refs, name) != NULL) > + return 0; /* already exists */ > Here we leak the name var. -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Tue Jan 31 21:36:04 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:36:04 -0200 Subject: [Libvirt-cim] [PATCH 1/3] libxkutil: Linked list helper In-Reply-To: <1328043984-12742-2-git-send-email-eblima@linux.vnet.ibm.com> References: <1328043984-12742-1-git-send-email-eblima@linux.vnet.ibm.com> <1328043984-12742-2-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F285EC4.4050005@linux.vnet.ibm.com> On 01/31/2012 07:06 PM, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > Signed-off-by: Eduardo Lima (Etrunko) > --- > libxkutil/Makefile.am | 51 +++++++--- > libxkutil/list_util.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++++ > libxkutil/list_util.h | 73 ++++++++++++++ > 3 files changed, 364 insertions(+), 14 deletions(-) > create mode 100644 libxkutil/list_util.c > create mode 100644 libxkutil/list_util.h > > diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am > index f1adc03..8d436ad 100644 > --- a/libxkutil/Makefile.am > +++ b/libxkutil/Makefile.am > @@ -1,21 +1,44 @@ > # Copyright IBM Corp. 2007 > +AM_CFLAGS = \ > + $(CFLAGS_STRICT) \ > + -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" > > -AM_CFLAGS = $(CFLAGS_STRICT) \ > - -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" > +noinst_HEADERS = \ > + cs_util.h \ > + misc_util.h \ > + device_parsing.h \ > + xmlgen.h \ > + infostore.h \ > + pool_parsing.h \ > + acl_parsing.h \ > + list_util.h > > -noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ > - pool_parsing.h acl_parsing.h > +lib_LTLIBRARIES = \ > + libxkutil.la > > -lib_LTLIBRARIES = libxkutil.la > +libxkutil_la_SOURCES = \ > + cs_util_instance.c \ > + misc_util.c \ > + device_parsing.c \ > + xmlgen.c \ > + infostore.c \ > + pool_parsing.c \ > + acl_parsing.c \ > + list_util.c > > -libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ > - xmlgen.c infostore.c pool_parsing.c acl_parsing.c > -libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ > -libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ > - @LIBUUID_LIBS@ > +libxkutil_la_LDFLAGS = \ > + -version-info @VERSION_INFO@ > > -noinst_PROGRAMS = xml_parse_test > +libxkutil_la_LIBADD = \ > + @LIBVIRT_LIBS@ \ > + @LIBUUID_LIBS@ > > -xml_parse_test_SOURCES = xml_parse_test.c > -xml_parse_test_LDADD = libxkutil.la \ > - @LIBVIRT_LIBS@ > +noinst_PROGRAMS = \ > + xml_parse_test > + > +xml_parse_test_SOURCES = \ > + xml_parse_test.c > + > +xml_parse_test_LDADD = \ > + libxkutil.la \ > + @LIBVIRT_LIBS@ > diff --git a/libxkutil/list_util.c b/libxkutil/list_util.c > new file mode 100644 > index 0000000..dc3629f > --- /dev/null > +++ b/libxkutil/list_util.c > @@ -0,0 +1,254 @@ > +/* > + * Copyright IBM Corp. 2012 > + * > + * Authors: > + * Eduardo Lima (Etrunko) > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > + */ > +#ifdef HAVE_CONFIG_H > +# include "config.h" > +#endif > + > +#include > + > +#include "list_util.h" > + > +struct _list_node_t { > + list_node_t *prev; > + list_node_t *next; > + void *data; > +}; > + > +struct _list_t { > + unsigned int count; > + list_node_t *head; > + list_data_free_cb free_cb; > + list_data_cmp_cb cmp_cb; > +}; > + > +list_t *list_new(list_data_free_cb free_cb, list_data_cmp_cb cmp_cb) > +{ > + list_t *l = calloc(1, sizeof(*l)); > + if (l == NULL) > + return NULL; > + > + l->free_cb = free_cb; > + l->cmp_cb = cmp_cb; > + return l; > +} > + > +void list_free(list_t *list) > +{ > + list_node_t *n, *next; > + > + if (list == NULL || list->head == NULL) > + return; > + > + n = list->head; > + > + do { > + if (list->free_cb) > + list->free_cb(n->data); > + > + next = n->next; > + free(n); > + n = next; > + } while (n != list->head); > + > + free(list); > +} > + > +void list_append(list_t *list, void *data) > +{ > + list_node_t *n; > + > + if (list == NULL) > + return; > + > + n = calloc(1, sizeof(*n)); > + > + if (n == NULL) > + return; > + > + n->data = data; > + > + if (list->head == NULL) { /* empty list */ > + n->next = n->prev = n; > + list->head = n; > + goto end; > + } > + > + n->next = list->head; > + n->prev = list->head->prev; > + > + list->head->prev->next = n; > + list->head->prev = n; > + > + end: > + list->count += 1; > +} > + > +void list_prepend(list_t *list, void *data) > +{ > + list_append(list, data); > + list->head = list->head->prev; > +} > + > +void *list_find(list_t *list, void *user_data) > +{ > + list_node_t *n = list_find_node(list, user_data); > + return list_node_data_get(n); > +} > + > +list_node_t *list_find_node(list_t *list, void *user_data) > +{ > + list_node_t *n; > + > + if (list == NULL || list->head == NULL || list->cmp_cb == NULL) > + return NULL; > + > + n = list->head; > + do { > + if (list->cmp_cb(n->data, user_data) == 0) > + return n; > + > + n = n->next; > + } while (n != list->head); > + > + return NULL; > +} > + > +void list_remove(list_t *list, void *data) > +{ > + list_node_t *n = list_find_node(list, data); > + list_remove_node(list, n); > +} > + > +void list_remove_node(list_t *list, list_node_t *node) > +{ > + if (list == NULL || list->head == NULL || node == NULL) > + return; > + > + if (node->next == node) { /* only 1 item */ > + list->head = NULL; > + } else { > + if (node == list->head) /* first node */ > + list->head = node->next; > + > + node->prev->next = node->next; > + node->next->prev = node->prev; > + } > + > + if (list->free_cb) > + list->free_cb(node->data); > + > + free(node); > + list->count -= 1; > +} > + > +bool list_foreach(list_t *list, list_foreach_cb cb, void *user_data) > +{ > + list_node_t *node; > + > + if (list == NULL || list->head == NULL) > + return true; /* nothing to do */ > + > + node = list->head; > + do { > + if (cb(node->data, user_data) == false) > + return false; > + > + node = node->next; > + } while (node != list->head); > + > + return true; > +} > + > +unsigned int list_count(list_t *list) > +{ > + if (list == NULL) > + return 0; > + > + return list->count; > +} > + > +void *list_node_data_get(list_node_t *node) > +{ > + if (node == NULL) > + return NULL; > + > + return node->data; > +} > + > +void list_node_data_set(list_node_t *node, void *data) > +{ > + if (node == NULL) > + return; > + > + node->data = data; > +} > + > +void *list_first(list_t *list) > +{ > + return list_node_data_get(list->head); > +} > + > +list_node_t *list_first_node(list_t *list) > +{ > + if (list == NULL) > + return NULL; > + > + return list->head; > +} > + > +void *list_last(list_t *list) > +{ > + return list_node_data_get(list_last_node(list)); > +} > + > +list_node_t *list_last_node(list_t *list) > +{ > + if (list == NULL) > + return NULL; > + Possible NULL dereference if list->head == NULL. Should be: + if (list == NULL || list->head == NULL) + return NULL; + > + return list->head->prev; > +} -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Tue Jan 31 21:39:54 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:39:54 -0200 Subject: [Libvirt-cim] [PATCH 3/3] ACL: Use linked list helper for filter refs In-Reply-To: <1328045994-15198-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1328045994-15198-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1328045994-15198-4-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/acl_parsing.c | 58 +++++++++------------------------ libxkutil/acl_parsing.h | 5 ++- libxkutil/xmlgen.c | 30 +++++++++++++---- src/Virt_NestedFilterList.c | 73 +++++++++++++++++++++++------------------- 4 files changed, 82 insertions(+), 84 deletions(-) diff --git a/libxkutil/acl_parsing.c b/libxkutil/acl_parsing.c index 9c4b4b2..6dd481b 100644 --- a/libxkutil/acl_parsing.c +++ b/libxkutil/acl_parsing.c @@ -141,11 +141,7 @@ void cleanup_filter(struct acl_filter *filter) free(filter->rules); filter->rule_ct = 0; - for (i = 0; i < filter->ref_ct; i++) - free(filter->refs[i]); - - free(filter->refs); - filter->ref_ct = 0; + list_free(filter->refs); } void cleanup_filters(struct acl_filter **filters, int count) @@ -610,58 +606,36 @@ int append_filter_rule(struct acl_filter *filter, struct acl_rule *rule) return 1; } -int append_filter_ref(struct acl_filter *filter, char *name) + +static int filter_ref_cmp(void *list_data, void *user_data) { - int i; - char **old_refs = NULL; + return strcmp((const char *)list_data, (const char *) user_data); +} - if ((filter == NULL) || (name == NULL)) +int append_filter_ref(struct acl_filter *filter, char *name) +{ + if (filter == NULL || name == NULL) return 0; - for (i = 0; i < filter->ref_ct; i++) - if (STREQC(filter->refs[i], name)) - return 0; /* already exists */ - - old_refs = filter->refs; - - filter->refs = malloc((filter->ref_ct + 1) * sizeof(char *)); + if (filter->refs == NULL) + filter->refs = list_new(free, filter_ref_cmp); - if (filter->refs == NULL) { - CU_DEBUG("Failed to allocate memory for new ref"); - filter->refs = old_refs; - return 0; + if (list_find(filter->refs, name) != NULL) { + free(name); + return 0; /* already exists */ } - memcpy(filter->refs, old_refs, filter->ref_ct * sizeof(char *)); - - filter->refs[filter->ref_ct] = name; - filter->ref_ct++; - - free(old_refs); + list_append(filter->refs, name); return 1; } int remove_filter_ref(struct acl_filter *filter, const char *name) { - int i; - char **old_refs = NULL; - - if ((filter == NULL) || (name == NULL)) + if (filter == NULL || filter->refs == NULL || name == NULL) return 0; - /* TODO: called infrequently, but needs optimization */ - old_refs = filter->refs; - filter->ref_ct = 0; - - for (i = 0; i < filter->ref_ct; i++) { - if (STREQC(old_refs[i], name)) { - free(old_refs[i]); - } - else if(append_filter_ref(filter, old_refs[i]) == 0) { - return 0; - } - } + list_remove(filter->refs, (void *) name); return 1; } diff --git a/libxkutil/acl_parsing.h b/libxkutil/acl_parsing.h index 5b99175..e49f384 100644 --- a/libxkutil/acl_parsing.h +++ b/libxkutil/acl_parsing.h @@ -26,6 +26,8 @@ #include #include +#include "list_util.h" + struct acl_mac_rule { char *srcmacaddr; char *srcmacmask; @@ -152,8 +154,7 @@ struct acl_filter { struct acl_rule **rules; int rule_ct; - char **refs; - int ref_ct; + list_t *refs; }; void cleanup_rule(struct acl_rule *rule); diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index 9a2ada9..5c16ebe 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -28,6 +28,7 @@ #include #include "xmlgen.h" +#include "list_util.h" #ifndef TEST #include "misc_util.h" @@ -1467,12 +1468,31 @@ char *res_to_xml(struct virt_pool_res *res) { return xml; } +static bool filter_ref_foreach(void *list_data, void *user_data) +{ + char *filter = (char *) list_data; + xmlNodePtr root = (xmlNodePtr) user_data; + xmlNodePtr tmp = NULL; + + tmp = xmlNewChild(root, NULL, BAD_CAST "filterref", NULL); + if (tmp == NULL) { + CU_DEBUG("Error creating filterref node"); + return false; + } + + if (xmlNewProp(tmp, BAD_CAST "filter", BAD_CAST list_data) == NULL) { + CU_DEBUG("Error adding filter attribute '%s'", filter); + return false; + } + + return true; +} + char *filter_to_xml(struct acl_filter *filter) { char *xml = NULL; xmlNodePtr root = NULL; xmlNodePtr tmp = NULL; - int i; root = xmlNewNode(NULL, BAD_CAST "filter"); if (root == NULL) @@ -1494,12 +1514,8 @@ char *filter_to_xml(struct acl_filter *filter) goto out; } - for (i = 0; i < filter->ref_ct; i++) { - tmp = xmlNewChild(root, NULL, BAD_CAST "filterref", NULL); - if (xmlNewProp(tmp, BAD_CAST "filter", - BAD_CAST filter->refs[i]) == NULL) - goto out; - } + if (!list_foreach(filter->refs, filter_ref_foreach, (void *) root)) + goto out; xml = tree_to_xml(root); diff --git a/src/Virt_NestedFilterList.c b/src/Virt_NestedFilterList.c index 81c4408..a8565d6 100644 --- a/src/Virt_NestedFilterList.c +++ b/src/Virt_NestedFilterList.c @@ -34,6 +34,7 @@ #include "acl_parsing.h" #include "misc_util.h" +#include "list_util.h" #include "Virt_FilterList.h" static const CMPIBroker *_BROKER; @@ -120,7 +121,7 @@ static CMPIStatus parent_to_child( CMPIInstance *instance = NULL; const char * name = NULL; virConnectPtr conn = NULL; - int i; + list_node_t *head, *node; CU_DEBUG("Reference = %s", REF2STR(reference)); @@ -139,29 +140,39 @@ static CMPIStatus parent_to_child( if (parent_filter == NULL) goto out; - for (i = 0; i < parent_filter->ref_ct; i++) { - get_filter_by_name(conn, parent_filter->refs[i], - &child_filter); - if (child_filter == NULL) - continue; - - CU_DEBUG("Processing %s,", child_filter->name); - - s = instance_from_filter(_BROKER, - info->context, - reference, - child_filter, - &instance); + /* Walk refs list */ + if (parent_filter->refs == NULL) + goto end; + + head = node = list_first_node(parent_filter->refs); + if (head == NULL) + goto end; + + do { + name = (const char *) list_node_data_get(node); + get_filter_by_name(conn, name, &child_filter); + if (child_filter != NULL) { + CU_DEBUG("Processing %s,", child_filter->name); + + s = instance_from_filter(_BROKER, + info->context, + reference, + child_filter, + &instance); + + if (instance != NULL) { + CU_DEBUG("Adding instance to inst_list"); + inst_list_add(list, instance); + } - if (instance != NULL) { - CU_DEBUG("Adding instance to inst_list"); - inst_list_add(list, instance); + cleanup_filters(&child_filter, 1); } - cleanup_filters(&child_filter, 1); instance = NULL; - } + node = list_node_next_node(node); + } while (node != head); + end: cleanup_filters(&parent_filter, 1); out: @@ -183,7 +194,7 @@ static CMPIStatus child_to_parent( CMPIInstance *instance = NULL; const char *name = NULL; virConnectPtr conn = NULL; - int count, i, j; + int count, i; CU_DEBUG("Reference = %s", REF2STR(reference)); @@ -206,24 +217,20 @@ static CMPIStatus child_to_parent( /* return any filter that has name in refs */ for (i = 0; i < count; i++) { - for (j = 0; j < _list[i].ref_ct; j++) { - if (STREQC(name, _list[i].refs[j])) { - CU_DEBUG("Processing %s,", _list[i].name); + if (list_find_node(_list[i].refs, (void *) name) != NULL) { + CU_DEBUG("Processing %s,", _list[i].name); - s = instance_from_filter(_BROKER, - info->context, - reference, - &_list[i], - &instance); - - if (instance != NULL) - inst_list_add(list, instance); + s = instance_from_filter(_BROKER, + info->context, + reference, + &_list[i], + &instance); + if (instance != NULL) { + inst_list_add(list, instance); instance = NULL; } - } - } cleanup_filters(&_list, count); -- 1.7.7.6 From eblima at linux.vnet.ibm.com Tue Jan 31 21:39:51 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:39:51 -0200 Subject: [Libvirt-cim] [PATCH v5 0/3] Implementation of a linked list helper Message-ID: <1328045994-15198-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" This series provides a generic linked list implementation for libxkutil that is based on the one originally developed for the libvirt domain events support recently integrated upstream. As test case I ported the ComputerSystemIndication provider code to use this list implementation. In the near future it will be also used by the event loop that I am currently working on to allow systems with libvirt older than 0.9.0 to make use of the same feature. Other possible use cases would be to port the code of libxkutil/*_parsing* to also use the list implementation instead of static arrays. Changes from v4: - Fix possible NULL dereference in list_last_node() - Fix possible leak in acl_parsing.c Changes from v3: - Fix crashes in list_free(), list_first_node() and list_count() - Include patch that ports the acl filter ref code to use the linked list implementation Changes from v2: - Make list struct private Changes from v1: - Fix version iformation in Makefile.am Eduardo Lima (Etrunko) (3): libxkutil: Linked list helper CSI: Use list helper implementation ACL: Use linked list helper for filter refs libxkutil/Makefile.am | 51 +++++-- libxkutil/acl_parsing.c | 58 +++------ libxkutil/acl_parsing.h | 5 +- libxkutil/list_util.c | 254 +++++++++++++++++++++++++++++++++++ libxkutil/list_util.h | 73 ++++++++++ libxkutil/xmlgen.c | 30 +++- src/Virt_ComputerSystemIndication.c | 95 ++++---------- src/Virt_NestedFilterList.c | 73 ++++++----- 8 files changed, 472 insertions(+), 167 deletions(-) create mode 100644 libxkutil/list_util.c create mode 100644 libxkutil/list_util.h -- 1.7.7.6 From eblima at linux.vnet.ibm.com Tue Jan 31 21:39:53 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:39:53 -0200 Subject: [Libvirt-cim] [PATCH 2/3] CSI: Use list helper implementation In-Reply-To: <1328045994-15198-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1328045994-15198-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1328045994-15198-3-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- src/Virt_ComputerSystemIndication.c | 95 ++++++++++------------------------- 1 files changed, 26 insertions(+), 69 deletions(-) diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c index 6ef2ddc..712e12c 100644 --- a/src/Virt_ComputerSystemIndication.c +++ b/src/Virt_ComputerSystemIndication.c @@ -19,6 +19,10 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #include #include @@ -34,11 +38,11 @@ #include #include -#include #include -#include -#include "config.h" +#include +#include +#include #include "Virt_ComputerSystem.h" #include "Virt_ComputerSystemIndication.h" @@ -64,8 +68,6 @@ struct _csi_dom_xml_t { char uuid[VIR_UUID_STRING_BUFLEN]; char *name; char *xml; - csi_dom_xml_t *next; - csi_dom_xml_t *prev; }; typedef struct _csi_thread_data_t csi_thread_data_t; @@ -73,7 +75,7 @@ struct _csi_thread_data_t { CMPI_THREAD_TYPE id; int active_filters; int dom_count; - csi_dom_xml_t *dom_list; + list_t *dom_list; struct ind_args *args; }; @@ -83,15 +85,24 @@ static bool lifecycle_enabled = false; static csi_thread_data_t csi_thread_data[CSI_NUM_PLATFORMS] = {{0}, {0}, {0}}; /* - * Domain list manipulation + * Domain manipulation */ -static void csi_dom_xml_free(csi_dom_xml_t *dom) +static void csi_dom_xml_free(void *data) { + csi_dom_xml_t *dom = (csi_dom_xml_t *) data; free(dom->xml); free(dom->name); free(dom); } +static int csi_dom_xml_cmp(void *data, void *cmp_cb_data) +{ + csi_dom_xml_t *dom = (csi_dom_xml_t *) data; + const char *uuid = (const char *) cmp_cb_data; + + return strcmp(dom->uuid, uuid); +} + static int csi_dom_xml_set(csi_dom_xml_t *dom, virDomainPtr dom_ptr, CMPIStatus *s) { const char *name; @@ -150,65 +161,10 @@ static csi_dom_xml_t *csi_dom_xml_new(virDomainPtr dom_ptr, CMPIStatus *s) static void csi_thread_dom_list_append(csi_thread_data_t *thread, csi_dom_xml_t *dom) { - /* empty list */ - if (thread->dom_list == NULL) { - dom->next = dom->prev = dom; - thread->dom_list = dom; - goto end; - } - - dom->next = thread->dom_list; - dom->prev = thread->dom_list->prev; - - thread->dom_list->prev->next = dom; - thread->dom_list->prev = dom; - - end: - thread->dom_count += 1; -} - -static csi_dom_xml_t *csi_thread_dom_list_find(csi_thread_data_t *thread, - const char *uuid) -{ - csi_dom_xml_t *dom; - if (thread->dom_list == NULL) - return NULL; - - dom = thread->dom_list; - - do { - if (STREQ(dom->uuid, uuid)) - return dom; - - dom = dom->next; - } while (dom != thread->dom_list); + thread->dom_list = list_new(csi_dom_xml_free, csi_dom_xml_cmp); - return NULL; -} - -static void csi_thread_dom_list_remove(csi_thread_data_t *thread, - csi_dom_xml_t *dom) -{ - if (dom->next == dom) { /* Only one node */ - thread->dom_list = NULL; - } else { - if (thread->dom_list == dom) /* First node */ - thread->dom_list = dom->next; - - dom->prev->next = dom->next; - dom->next->prev = dom->prev; - } - - thread->dom_count -= 1; - - csi_dom_xml_free(dom); -} - -static void csi_thread_dom_list_free(csi_thread_data_t *thread) -{ - while(thread->dom_list != NULL) - csi_thread_dom_list_remove(thread, thread->dom_list); + list_append(thread->dom_list, dom); } static void csi_free_thread_data(void *data) @@ -218,7 +174,8 @@ static void csi_free_thread_data(void *data) if (data == NULL) return; - csi_thread_dom_list_free(thread); + list_free(thread->dom_list); + thread->dom_list = NULL; stdi_free_ind_args(&thread->args); } @@ -512,7 +469,7 @@ static int update_domain_list(virConnectPtr conn, csi_thread_data_t *thread) CMPIStatus s = {CMPI_RC_OK, NULL}; int i, count; - csi_thread_dom_list_free(thread); + list_free(thread->dom_list); count = get_domain_list(conn, &dom_ptr_list); @@ -574,7 +531,7 @@ static int csi_domain_event_cb(virConnectPtr conn, if (cs_event != CS_CREATED) { char uuid[VIR_UUID_STRING_BUFLEN] = {0}; virDomainGetUUIDString(dom, &uuid[0]); - dom_xml = csi_thread_dom_list_find(thread, uuid); + dom_xml = list_find(thread->dom_list, uuid); } if (dom_xml == NULL) { @@ -595,7 +552,7 @@ static int csi_domain_event_cb(virConnectPtr conn, } } else if (event == VIR_DOMAIN_EVENT_DEFINED && detail == VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) { - csi_thread_dom_list_remove(thread, dom_xml); + list_remove(thread->dom_list, dom_xml); } end: -- 1.7.7.6 From eblima at linux.vnet.ibm.com Tue Jan 31 21:39:52 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:39:52 -0200 Subject: [Libvirt-cim] [PATCH 1/3] libxkutil: Linked list helper In-Reply-To: <1328045994-15198-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1328045994-15198-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1328045994-15198-2-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/Makefile.am | 51 +++++++--- libxkutil/list_util.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++++ libxkutil/list_util.h | 73 ++++++++++++++ 3 files changed, 364 insertions(+), 14 deletions(-) create mode 100644 libxkutil/list_util.c create mode 100644 libxkutil/list_util.h diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am index f1adc03..8d436ad 100644 --- a/libxkutil/Makefile.am +++ b/libxkutil/Makefile.am @@ -1,21 +1,44 @@ # Copyright IBM Corp. 2007 +AM_CFLAGS = \ + $(CFLAGS_STRICT) \ + -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" -AM_CFLAGS = $(CFLAGS_STRICT) \ - -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" +noinst_HEADERS = \ + cs_util.h \ + misc_util.h \ + device_parsing.h \ + xmlgen.h \ + infostore.h \ + pool_parsing.h \ + acl_parsing.h \ + list_util.h -noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ - pool_parsing.h acl_parsing.h +lib_LTLIBRARIES = \ + libxkutil.la -lib_LTLIBRARIES = libxkutil.la +libxkutil_la_SOURCES = \ + cs_util_instance.c \ + misc_util.c \ + device_parsing.c \ + xmlgen.c \ + infostore.c \ + pool_parsing.c \ + acl_parsing.c \ + list_util.c -libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ - xmlgen.c infostore.c pool_parsing.c acl_parsing.c -libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ -libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ - @LIBUUID_LIBS@ +libxkutil_la_LDFLAGS = \ + -version-info @VERSION_INFO@ -noinst_PROGRAMS = xml_parse_test +libxkutil_la_LIBADD = \ + @LIBVIRT_LIBS@ \ + @LIBUUID_LIBS@ -xml_parse_test_SOURCES = xml_parse_test.c -xml_parse_test_LDADD = libxkutil.la \ - @LIBVIRT_LIBS@ +noinst_PROGRAMS = \ + xml_parse_test + +xml_parse_test_SOURCES = \ + xml_parse_test.c + +xml_parse_test_LDADD = \ + libxkutil.la \ + @LIBVIRT_LIBS@ diff --git a/libxkutil/list_util.c b/libxkutil/list_util.c new file mode 100644 index 0000000..9b95864 --- /dev/null +++ b/libxkutil/list_util.c @@ -0,0 +1,254 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Eduardo Lima (Etrunko) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "list_util.h" + +struct _list_node_t { + list_node_t *prev; + list_node_t *next; + void *data; +}; + +struct _list_t { + unsigned int count; + list_node_t *head; + list_data_free_cb free_cb; + list_data_cmp_cb cmp_cb; +}; + +list_t *list_new(list_data_free_cb free_cb, list_data_cmp_cb cmp_cb) +{ + list_t *l = calloc(1, sizeof(*l)); + if (l == NULL) + return NULL; + + l->free_cb = free_cb; + l->cmp_cb = cmp_cb; + return l; +} + +void list_free(list_t *list) +{ + list_node_t *n, *next; + + if (list == NULL || list->head == NULL) + return; + + n = list->head; + + do { + if (list->free_cb) + list->free_cb(n->data); + + next = n->next; + free(n); + n = next; + } while (n != list->head); + + free(list); +} + +void list_append(list_t *list, void *data) +{ + list_node_t *n; + + if (list == NULL) + return; + + n = calloc(1, sizeof(*n)); + + if (n == NULL) + return; + + n->data = data; + + if (list->head == NULL) { /* empty list */ + n->next = n->prev = n; + list->head = n; + goto end; + } + + n->next = list->head; + n->prev = list->head->prev; + + list->head->prev->next = n; + list->head->prev = n; + + end: + list->count += 1; +} + +void list_prepend(list_t *list, void *data) +{ + list_append(list, data); + list->head = list->head->prev; +} + +void *list_find(list_t *list, void *user_data) +{ + list_node_t *n = list_find_node(list, user_data); + return list_node_data_get(n); +} + +list_node_t *list_find_node(list_t *list, void *user_data) +{ + list_node_t *n; + + if (list == NULL || list->head == NULL || list->cmp_cb == NULL) + return NULL; + + n = list->head; + do { + if (list->cmp_cb(n->data, user_data) == 0) + return n; + + n = n->next; + } while (n != list->head); + + return NULL; +} + +void list_remove(list_t *list, void *data) +{ + list_node_t *n = list_find_node(list, data); + list_remove_node(list, n); +} + +void list_remove_node(list_t *list, list_node_t *node) +{ + if (list == NULL || list->head == NULL || node == NULL) + return; + + if (node->next == node) { /* only 1 item */ + list->head = NULL; + } else { + if (node == list->head) /* first node */ + list->head = node->next; + + node->prev->next = node->next; + node->next->prev = node->prev; + } + + if (list->free_cb) + list->free_cb(node->data); + + free(node); + list->count -= 1; +} + +bool list_foreach(list_t *list, list_foreach_cb cb, void *user_data) +{ + list_node_t *node; + + if (list == NULL || list->head == NULL) + return true; /* nothing to do */ + + node = list->head; + do { + if (cb(node->data, user_data) == false) + return false; + + node = node->next; + } while (node != list->head); + + return true; +} + +unsigned int list_count(list_t *list) +{ + if (list == NULL) + return 0; + + return list->count; +} + +void *list_node_data_get(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->data; +} + +void list_node_data_set(list_node_t *node, void *data) +{ + if (node == NULL) + return; + + node->data = data; +} + +void *list_first(list_t *list) +{ + return list_node_data_get(list->head); +} + +list_node_t *list_first_node(list_t *list) +{ + if (list == NULL) + return NULL; + + return list->head; +} + +void *list_last(list_t *list) +{ + return list_node_data_get(list_last_node(list)); +} + +list_node_t *list_last_node(list_t *list) +{ + if (list == NULL || list->head == NULL) + return NULL; + + return list->head->prev; +} + +void *list_node_next(list_node_t *node) +{ + return list_node_data_get(list_node_next_node(node)); +} + +list_node_t *list_node_next_node(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->next; +} + +void *list_node_prev(list_node_t *node) +{ + return list_node_data_get(list_node_prev_node(node)); +} + +list_node_t *list_node_prev_node(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->prev; +} diff --git a/libxkutil/list_util.h b/libxkutil/list_util.h new file mode 100644 index 0000000..1809c2e --- /dev/null +++ b/libxkutil/list_util.h @@ -0,0 +1,73 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Eduardo Lima (Etrunko) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LIST_UTIL_H +#define __LIST_UTIL_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*list_data_free_cb)(void *data); +typedef int (*list_data_cmp_cb)(void *list_data, void *user_data); +typedef bool (*list_foreach_cb)(void *list_data, void *user_data); + +typedef struct _list_node_t list_node_t; +typedef struct _list_t list_t; + +list_t *list_new(list_data_free_cb free_cb, list_data_cmp_cb cmp_cb); +void list_free(list_t *list); + +void list_append(list_t *list, void *data); +void list_prepend(list_t *list, void *data); + +void *list_find(list_t *list, void *user_data); +list_node_t *list_find_node(list_t *list, void *user_data); + +void list_remove(list_t *list, void *data); +void list_remove_node(list_t *list, list_node_t *node); + +bool list_foreach(list_t *list, list_foreach_cb cb, void *user_data); + +inline unsigned int list_count(list_t *list); + +inline void *list_node_data_get(list_node_t *node); +inline void list_node_data_set(list_node_t *node, void *data); + +inline void *list_first(list_t *list); +inline list_node_t *list_first_node(list_t *list); + +inline void *list_last(list_t *list); +inline list_node_t *list_last_node(list_t *list); + +inline void *list_node_next(list_node_t *node); +inline list_node_t *list_node_next_node(list_node_t *node); + +inline void *list_node_prev(list_node_t *node); +inline list_node_t *list_node_prev_node(list_node_t *node); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __LIST_UTIL_H */ -- 1.7.7.6 From eblima at linux.vnet.ibm.com Tue Jan 31 21:52:42 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:52:42 -0200 Subject: [Libvirt-cim] [PATCH 3/4] FilterEntry: Update action property In-Reply-To: <1328043642.4193.1272.camel@snmishra-desktop.beaverton.ibm.com> References: <1327967871-24219-1-git-send-email-eblima@linux.vnet.ibm.com> <1327967871-24219-4-git-send-email-eblima@linux.vnet.ibm.com> <1328043642.4193.1272.camel@snmishra-desktop.beaverton.ibm.com> Message-ID: <4F2862AA.6000509@linux.vnet.ibm.com> On 01/31/2012 07:00 PM, Sharad Mishra wrote: > seeing following issue now - > > FilterList - 01_enum.py: PASS > -------------------------------------------------------------------- > FilterList - 02_assoc.py: FAIL > ERROR - CIMError : (1, u'CIM_ERR_FAILED: Failed to load the Provider > Manager for interface type "CMPI" from library "".') > Traceback (most recent call last): > File > "/tmp/remove_me/cimtest/suites/libvirt-cim/lib/XenKvmLib/const.py", line > 141, in do_try > rc = f() > File "02_assoc.py", line 50, in main > cim_filters = _test.cim_entries_in_filter_lists() > File > "/tmp/remove_me/cimtest/suites/libvirt-cim/cimtest/FilterList/helper.py", line 269, in cim_entries_in_filter_lists > l.extend(self.Associators(n, result_class="CIM_FilterEntryBase")) > File > "/tmp/remove_me/cimtest/suites/libvirt-cim/cimtest/FilterList/helper.py", line 88, in Associators > return self.wbem.Associators(typed_class, **kargs) > File "/usr/lib/python2.6/site-packages/pywbem/cim_operations.py", line > 696, in Associators > **params) > File "/usr/lib/python2.6/site-packages/pywbem/cim_operations.py", line > 219, in imethodcall > raise CIMError(code, tt[1]['DESCRIPTION']) > CIMError: (1, u'CIM_ERR_FAILED: Failed to load the Provider Manager for > interface type "CMPI" from library "".') > ERROR - None > -------------------------------------------------------------------- > FilterList - 03_create.py: PASS > > I don't think this error is related to this patch right? Anyway, I don't see any failures with FilterList tests anymore. See the log attached. Best regards, -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com -------------- next part -------------- A non-text attachment was scrubbed... Name: cimtest.log Type: text/x-log Size: 47378 bytes Desc: not available URL: From eblima at linux.vnet.ibm.com Tue Jan 31 21:55:34 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:55:34 -0200 Subject: [Libvirt-cim] [PATCH 1/3] libxkutil: Linked list helper In-Reply-To: <1328045994-15198-2-git-send-email-eblima@linux.vnet.ibm.com> References: <1328045994-15198-1-git-send-email-eblima@linux.vnet.ibm.com> <1328045994-15198-2-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <4F286356.4060602@linux.vnet.ibm.com> On 01/31/2012 07:39 PM, Eduardo Lima (Etrunko) wrote: > From: "Eduardo Lima (Etrunko)" > > Signed-off-by: Eduardo Lima (Etrunko) > --- > libxkutil/Makefile.am | 51 +++++++--- > libxkutil/list_util.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++++ > libxkutil/list_util.h | 73 ++++++++++++++ > 3 files changed, 364 insertions(+), 14 deletions(-) > create mode 100644 libxkutil/list_util.c > create mode 100644 libxkutil/list_util.h > > diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am > index f1adc03..8d436ad 100644 > --- a/libxkutil/Makefile.am > +++ b/libxkutil/Makefile.am > @@ -1,21 +1,44 @@ > # Copyright IBM Corp. 2007 > +AM_CFLAGS = \ > + $(CFLAGS_STRICT) \ > + -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" > > -AM_CFLAGS = $(CFLAGS_STRICT) \ > - -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" > +noinst_HEADERS = \ > + cs_util.h \ > + misc_util.h \ > + device_parsing.h \ > + xmlgen.h \ > + infostore.h \ > + pool_parsing.h \ > + acl_parsing.h \ > + list_util.h > > -noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ > - pool_parsing.h acl_parsing.h > +lib_LTLIBRARIES = \ > + libxkutil.la > > -lib_LTLIBRARIES = libxkutil.la > +libxkutil_la_SOURCES = \ > + cs_util_instance.c \ > + misc_util.c \ > + device_parsing.c \ > + xmlgen.c \ > + infostore.c \ > + pool_parsing.c \ > + acl_parsing.c \ > + list_util.c > > -libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ > - xmlgen.c infostore.c pool_parsing.c acl_parsing.c > -libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ > -libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ > - @LIBUUID_LIBS@ > +libxkutil_la_LDFLAGS = \ > + -version-info @VERSION_INFO@ > > -noinst_PROGRAMS = xml_parse_test > +libxkutil_la_LIBADD = \ > + @LIBVIRT_LIBS@ \ > + @LIBUUID_LIBS@ > > -xml_parse_test_SOURCES = xml_parse_test.c > -xml_parse_test_LDADD = libxkutil.la \ > - @LIBVIRT_LIBS@ > +noinst_PROGRAMS = \ > + xml_parse_test > + > +xml_parse_test_SOURCES = \ > + xml_parse_test.c > + > +xml_parse_test_LDADD = \ > + libxkutil.la \ > + @LIBVIRT_LIBS@ > diff --git a/libxkutil/list_util.c b/libxkutil/list_util.c > new file mode 100644 > index 0000000..9b95864 > --- /dev/null > +++ b/libxkutil/list_util.c > @@ -0,0 +1,254 @@ > +/* > + * Copyright IBM Corp. 2012 > + * > + * Authors: > + * Eduardo Lima (Etrunko) > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > + */ > +#ifdef HAVE_CONFIG_H > +# include "config.h" > +#endif > + > +#include > + > +#include "list_util.h" > + > +struct _list_node_t { > + list_node_t *prev; > + list_node_t *next; > + void *data; > +}; > + > +struct _list_t { > + unsigned int count; > + list_node_t *head; > + list_data_free_cb free_cb; > + list_data_cmp_cb cmp_cb; > +}; > + > +list_t *list_new(list_data_free_cb free_cb, list_data_cmp_cb cmp_cb) > +{ > + list_t *l = calloc(1, sizeof(*l)); > + if (l == NULL) > + return NULL; > + > + l->free_cb = free_cb; > + l->cmp_cb = cmp_cb; > + return l; > +} > + > +void list_free(list_t *list) > +{ > + list_node_t *n, *next; > + > + if (list == NULL || list->head == NULL) > + return; > + > + n = list->head; > + > + do { > + if (list->free_cb) > + list->free_cb(n->data); > + > + next = n->next; > + free(n); > + n = next; > + } while (n != list->head); > + > + free(list); > +} > + > +void list_append(list_t *list, void *data) > +{ > + list_node_t *n; > + > + if (list == NULL) > + return; > + > + n = calloc(1, sizeof(*n)); > + > + if (n == NULL) > + return; > + > + n->data = data; > + > + if (list->head == NULL) { /* empty list */ > + n->next = n->prev = n; > + list->head = n; > + goto end; > + } > + > + n->next = list->head; > + n->prev = list->head->prev; > + > + list->head->prev->next = n; > + list->head->prev = n; > + > + end: > + list->count += 1; > +} > + > +void list_prepend(list_t *list, void *data) > +{ > + list_append(list, data); > + list->head = list->head->prev; > +} > + > +void *list_find(list_t *list, void *user_data) > +{ > + list_node_t *n = list_find_node(list, user_data); > + return list_node_data_get(n); > +} > + > +list_node_t *list_find_node(list_t *list, void *user_data) > +{ > + list_node_t *n; > + > + if (list == NULL || list->head == NULL || list->cmp_cb == NULL) > + return NULL; > + > + n = list->head; > + do { > + if (list->cmp_cb(n->data, user_data) == 0) > + return n; > + > + n = n->next; > + } while (n != list->head); > + > + return NULL; > +} > + > +void list_remove(list_t *list, void *data) > +{ > + list_node_t *n = list_find_node(list, data); > + list_remove_node(list, n); > +} > + > +void list_remove_node(list_t *list, list_node_t *node) > +{ > + if (list == NULL || list->head == NULL || node == NULL) > + return; > + > + if (node->next == node) { /* only 1 item */ > + list->head = NULL; > + } else { > + if (node == list->head) /* first node */ > + list->head = node->next; > + > + node->prev->next = node->next; > + node->next->prev = node->prev; > + } > + > + if (list->free_cb) > + list->free_cb(node->data); > + > + free(node); > + list->count -= 1; > +} > + > +bool list_foreach(list_t *list, list_foreach_cb cb, void *user_data) > +{ > + list_node_t *node; > + > + if (list == NULL || list->head == NULL) > + return true; /* nothing to do */ > + > + node = list->head; > + do { > + if (cb(node->data, user_data) == false) > + return false; > + > + node = node->next; > + } while (node != list->head); > + > + return true; > +} > + > +unsigned int list_count(list_t *list) > +{ > + if (list == NULL) > + return 0; > + > + return list->count; > +} > + > +void *list_node_data_get(list_node_t *node) > +{ > + if (node == NULL) > + return NULL; > + > + return node->data; > +} > + > +void list_node_data_set(list_node_t *node, void *data) > +{ > + if (node == NULL) > + return; > + > + node->data = data; > +} > + > +void *list_first(list_t *list) > +{ > + return list_node_data_get(list->head); I am very sorry. I should pay more attention to the details, but I just saw another potential NULL dereference here. It should actually be the same as list_last() + return list_node_data_get(list_first_node(list)); -- Eduardo de Barros Lima Software Engineer, Open Virtualization Linux Technology Center - IBM/Brazil eblima at br.ibm.com From eblima at linux.vnet.ibm.com Tue Jan 31 21:58:43 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:58:43 -0200 Subject: [Libvirt-cim] [PATCH 1/3] libxkutil: Linked list helper In-Reply-To: <1328047125-22037-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1328047125-22037-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1328047125-22037-2-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/Makefile.am | 51 +++++++--- libxkutil/list_util.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++++ libxkutil/list_util.h | 73 ++++++++++++++ 3 files changed, 364 insertions(+), 14 deletions(-) create mode 100644 libxkutil/list_util.c create mode 100644 libxkutil/list_util.h diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am index f1adc03..8d436ad 100644 --- a/libxkutil/Makefile.am +++ b/libxkutil/Makefile.am @@ -1,21 +1,44 @@ # Copyright IBM Corp. 2007 +AM_CFLAGS = \ + $(CFLAGS_STRICT) \ + -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" -AM_CFLAGS = $(CFLAGS_STRICT) \ - -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .conf\" +noinst_HEADERS = \ + cs_util.h \ + misc_util.h \ + device_parsing.h \ + xmlgen.h \ + infostore.h \ + pool_parsing.h \ + acl_parsing.h \ + list_util.h -noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ - pool_parsing.h acl_parsing.h +lib_LTLIBRARIES = \ + libxkutil.la -lib_LTLIBRARIES = libxkutil.la +libxkutil_la_SOURCES = \ + cs_util_instance.c \ + misc_util.c \ + device_parsing.c \ + xmlgen.c \ + infostore.c \ + pool_parsing.c \ + acl_parsing.c \ + list_util.c -libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ - xmlgen.c infostore.c pool_parsing.c acl_parsing.c -libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ -libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ - @LIBUUID_LIBS@ +libxkutil_la_LDFLAGS = \ + -version-info @VERSION_INFO@ -noinst_PROGRAMS = xml_parse_test +libxkutil_la_LIBADD = \ + @LIBVIRT_LIBS@ \ + @LIBUUID_LIBS@ -xml_parse_test_SOURCES = xml_parse_test.c -xml_parse_test_LDADD = libxkutil.la \ - @LIBVIRT_LIBS@ +noinst_PROGRAMS = \ + xml_parse_test + +xml_parse_test_SOURCES = \ + xml_parse_test.c + +xml_parse_test_LDADD = \ + libxkutil.la \ + @LIBVIRT_LIBS@ diff --git a/libxkutil/list_util.c b/libxkutil/list_util.c new file mode 100644 index 0000000..84b2ba0 --- /dev/null +++ b/libxkutil/list_util.c @@ -0,0 +1,254 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Eduardo Lima (Etrunko) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "list_util.h" + +struct _list_node_t { + list_node_t *prev; + list_node_t *next; + void *data; +}; + +struct _list_t { + unsigned int count; + list_node_t *head; + list_data_free_cb free_cb; + list_data_cmp_cb cmp_cb; +}; + +list_t *list_new(list_data_free_cb free_cb, list_data_cmp_cb cmp_cb) +{ + list_t *l = calloc(1, sizeof(*l)); + if (l == NULL) + return NULL; + + l->free_cb = free_cb; + l->cmp_cb = cmp_cb; + return l; +} + +void list_free(list_t *list) +{ + list_node_t *n, *next; + + if (list == NULL || list->head == NULL) + return; + + n = list->head; + + do { + if (list->free_cb) + list->free_cb(n->data); + + next = n->next; + free(n); + n = next; + } while (n != list->head); + + free(list); +} + +void list_append(list_t *list, void *data) +{ + list_node_t *n; + + if (list == NULL) + return; + + n = calloc(1, sizeof(*n)); + + if (n == NULL) + return; + + n->data = data; + + if (list->head == NULL) { /* empty list */ + n->next = n->prev = n; + list->head = n; + goto end; + } + + n->next = list->head; + n->prev = list->head->prev; + + list->head->prev->next = n; + list->head->prev = n; + + end: + list->count += 1; +} + +void list_prepend(list_t *list, void *data) +{ + list_append(list, data); + list->head = list->head->prev; +} + +void *list_find(list_t *list, void *user_data) +{ + list_node_t *n = list_find_node(list, user_data); + return list_node_data_get(n); +} + +list_node_t *list_find_node(list_t *list, void *user_data) +{ + list_node_t *n; + + if (list == NULL || list->head == NULL || list->cmp_cb == NULL) + return NULL; + + n = list->head; + do { + if (list->cmp_cb(n->data, user_data) == 0) + return n; + + n = n->next; + } while (n != list->head); + + return NULL; +} + +void list_remove(list_t *list, void *data) +{ + list_node_t *n = list_find_node(list, data); + list_remove_node(list, n); +} + +void list_remove_node(list_t *list, list_node_t *node) +{ + if (list == NULL || list->head == NULL || node == NULL) + return; + + if (node->next == node) { /* only 1 item */ + list->head = NULL; + } else { + if (node == list->head) /* first node */ + list->head = node->next; + + node->prev->next = node->next; + node->next->prev = node->prev; + } + + if (list->free_cb) + list->free_cb(node->data); + + free(node); + list->count -= 1; +} + +bool list_foreach(list_t *list, list_foreach_cb cb, void *user_data) +{ + list_node_t *node; + + if (list == NULL || list->head == NULL) + return true; /* nothing to do */ + + node = list->head; + do { + if (cb(node->data, user_data) == false) + return false; + + node = node->next; + } while (node != list->head); + + return true; +} + +unsigned int list_count(list_t *list) +{ + if (list == NULL) + return 0; + + return list->count; +} + +void *list_node_data_get(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->data; +} + +void list_node_data_set(list_node_t *node, void *data) +{ + if (node == NULL) + return; + + node->data = data; +} + +void *list_first(list_t *list) +{ + return list_node_data_get(list_first_node(list)); +} + +list_node_t *list_first_node(list_t *list) +{ + if (list == NULL) + return NULL; + + return list->head; +} + +void *list_last(list_t *list) +{ + return list_node_data_get(list_last_node(list)); +} + +list_node_t *list_last_node(list_t *list) +{ + if (list == NULL || list->head == NULL) + return NULL; + + return list->head->prev; +} + +void *list_node_next(list_node_t *node) +{ + return list_node_data_get(list_node_next_node(node)); +} + +list_node_t *list_node_next_node(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->next; +} + +void *list_node_prev(list_node_t *node) +{ + return list_node_data_get(list_node_prev_node(node)); +} + +list_node_t *list_node_prev_node(list_node_t *node) +{ + if (node == NULL) + return NULL; + + return node->prev; +} diff --git a/libxkutil/list_util.h b/libxkutil/list_util.h new file mode 100644 index 0000000..1809c2e --- /dev/null +++ b/libxkutil/list_util.h @@ -0,0 +1,73 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Eduardo Lima (Etrunko) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LIST_UTIL_H +#define __LIST_UTIL_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*list_data_free_cb)(void *data); +typedef int (*list_data_cmp_cb)(void *list_data, void *user_data); +typedef bool (*list_foreach_cb)(void *list_data, void *user_data); + +typedef struct _list_node_t list_node_t; +typedef struct _list_t list_t; + +list_t *list_new(list_data_free_cb free_cb, list_data_cmp_cb cmp_cb); +void list_free(list_t *list); + +void list_append(list_t *list, void *data); +void list_prepend(list_t *list, void *data); + +void *list_find(list_t *list, void *user_data); +list_node_t *list_find_node(list_t *list, void *user_data); + +void list_remove(list_t *list, void *data); +void list_remove_node(list_t *list, list_node_t *node); + +bool list_foreach(list_t *list, list_foreach_cb cb, void *user_data); + +inline unsigned int list_count(list_t *list); + +inline void *list_node_data_get(list_node_t *node); +inline void list_node_data_set(list_node_t *node, void *data); + +inline void *list_first(list_t *list); +inline list_node_t *list_first_node(list_t *list); + +inline void *list_last(list_t *list); +inline list_node_t *list_last_node(list_t *list); + +inline void *list_node_next(list_node_t *node); +inline list_node_t *list_node_next_node(list_node_t *node); + +inline void *list_node_prev(list_node_t *node); +inline list_node_t *list_node_prev_node(list_node_t *node); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __LIST_UTIL_H */ -- 1.7.7.6 From eblima at linux.vnet.ibm.com Tue Jan 31 21:58:44 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:58:44 -0200 Subject: [Libvirt-cim] [PATCH 2/3] CSI: Use list helper implementation In-Reply-To: <1328047125-22037-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1328047125-22037-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1328047125-22037-3-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- src/Virt_ComputerSystemIndication.c | 95 ++++++++++------------------------- 1 files changed, 26 insertions(+), 69 deletions(-) diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c index 6ef2ddc..712e12c 100644 --- a/src/Virt_ComputerSystemIndication.c +++ b/src/Virt_ComputerSystemIndication.c @@ -19,6 +19,10 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #include #include @@ -34,11 +38,11 @@ #include #include -#include #include -#include -#include "config.h" +#include +#include +#include #include "Virt_ComputerSystem.h" #include "Virt_ComputerSystemIndication.h" @@ -64,8 +68,6 @@ struct _csi_dom_xml_t { char uuid[VIR_UUID_STRING_BUFLEN]; char *name; char *xml; - csi_dom_xml_t *next; - csi_dom_xml_t *prev; }; typedef struct _csi_thread_data_t csi_thread_data_t; @@ -73,7 +75,7 @@ struct _csi_thread_data_t { CMPI_THREAD_TYPE id; int active_filters; int dom_count; - csi_dom_xml_t *dom_list; + list_t *dom_list; struct ind_args *args; }; @@ -83,15 +85,24 @@ static bool lifecycle_enabled = false; static csi_thread_data_t csi_thread_data[CSI_NUM_PLATFORMS] = {{0}, {0}, {0}}; /* - * Domain list manipulation + * Domain manipulation */ -static void csi_dom_xml_free(csi_dom_xml_t *dom) +static void csi_dom_xml_free(void *data) { + csi_dom_xml_t *dom = (csi_dom_xml_t *) data; free(dom->xml); free(dom->name); free(dom); } +static int csi_dom_xml_cmp(void *data, void *cmp_cb_data) +{ + csi_dom_xml_t *dom = (csi_dom_xml_t *) data; + const char *uuid = (const char *) cmp_cb_data; + + return strcmp(dom->uuid, uuid); +} + static int csi_dom_xml_set(csi_dom_xml_t *dom, virDomainPtr dom_ptr, CMPIStatus *s) { const char *name; @@ -150,65 +161,10 @@ static csi_dom_xml_t *csi_dom_xml_new(virDomainPtr dom_ptr, CMPIStatus *s) static void csi_thread_dom_list_append(csi_thread_data_t *thread, csi_dom_xml_t *dom) { - /* empty list */ - if (thread->dom_list == NULL) { - dom->next = dom->prev = dom; - thread->dom_list = dom; - goto end; - } - - dom->next = thread->dom_list; - dom->prev = thread->dom_list->prev; - - thread->dom_list->prev->next = dom; - thread->dom_list->prev = dom; - - end: - thread->dom_count += 1; -} - -static csi_dom_xml_t *csi_thread_dom_list_find(csi_thread_data_t *thread, - const char *uuid) -{ - csi_dom_xml_t *dom; - if (thread->dom_list == NULL) - return NULL; - - dom = thread->dom_list; - - do { - if (STREQ(dom->uuid, uuid)) - return dom; - - dom = dom->next; - } while (dom != thread->dom_list); + thread->dom_list = list_new(csi_dom_xml_free, csi_dom_xml_cmp); - return NULL; -} - -static void csi_thread_dom_list_remove(csi_thread_data_t *thread, - csi_dom_xml_t *dom) -{ - if (dom->next == dom) { /* Only one node */ - thread->dom_list = NULL; - } else { - if (thread->dom_list == dom) /* First node */ - thread->dom_list = dom->next; - - dom->prev->next = dom->next; - dom->next->prev = dom->prev; - } - - thread->dom_count -= 1; - - csi_dom_xml_free(dom); -} - -static void csi_thread_dom_list_free(csi_thread_data_t *thread) -{ - while(thread->dom_list != NULL) - csi_thread_dom_list_remove(thread, thread->dom_list); + list_append(thread->dom_list, dom); } static void csi_free_thread_data(void *data) @@ -218,7 +174,8 @@ static void csi_free_thread_data(void *data) if (data == NULL) return; - csi_thread_dom_list_free(thread); + list_free(thread->dom_list); + thread->dom_list = NULL; stdi_free_ind_args(&thread->args); } @@ -512,7 +469,7 @@ static int update_domain_list(virConnectPtr conn, csi_thread_data_t *thread) CMPIStatus s = {CMPI_RC_OK, NULL}; int i, count; - csi_thread_dom_list_free(thread); + list_free(thread->dom_list); count = get_domain_list(conn, &dom_ptr_list); @@ -574,7 +531,7 @@ static int csi_domain_event_cb(virConnectPtr conn, if (cs_event != CS_CREATED) { char uuid[VIR_UUID_STRING_BUFLEN] = {0}; virDomainGetUUIDString(dom, &uuid[0]); - dom_xml = csi_thread_dom_list_find(thread, uuid); + dom_xml = list_find(thread->dom_list, uuid); } if (dom_xml == NULL) { @@ -595,7 +552,7 @@ static int csi_domain_event_cb(virConnectPtr conn, } } else if (event == VIR_DOMAIN_EVENT_DEFINED && detail == VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) { - csi_thread_dom_list_remove(thread, dom_xml); + list_remove(thread->dom_list, dom_xml); } end: -- 1.7.7.6 From eblima at linux.vnet.ibm.com Tue Jan 31 21:58:45 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:58:45 -0200 Subject: [Libvirt-cim] [PATCH 3/3] ACL: Use linked list helper for filter refs In-Reply-To: <1328047125-22037-1-git-send-email-eblima@linux.vnet.ibm.com> References: <1328047125-22037-1-git-send-email-eblima@linux.vnet.ibm.com> Message-ID: <1328047125-22037-4-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" Signed-off-by: Eduardo Lima (Etrunko) --- libxkutil/acl_parsing.c | 58 +++++++++------------------------ libxkutil/acl_parsing.h | 5 ++- libxkutil/xmlgen.c | 30 +++++++++++++---- src/Virt_NestedFilterList.c | 73 +++++++++++++++++++++++------------------- 4 files changed, 82 insertions(+), 84 deletions(-) diff --git a/libxkutil/acl_parsing.c b/libxkutil/acl_parsing.c index 9c4b4b2..6dd481b 100644 --- a/libxkutil/acl_parsing.c +++ b/libxkutil/acl_parsing.c @@ -141,11 +141,7 @@ void cleanup_filter(struct acl_filter *filter) free(filter->rules); filter->rule_ct = 0; - for (i = 0; i < filter->ref_ct; i++) - free(filter->refs[i]); - - free(filter->refs); - filter->ref_ct = 0; + list_free(filter->refs); } void cleanup_filters(struct acl_filter **filters, int count) @@ -610,58 +606,36 @@ int append_filter_rule(struct acl_filter *filter, struct acl_rule *rule) return 1; } -int append_filter_ref(struct acl_filter *filter, char *name) + +static int filter_ref_cmp(void *list_data, void *user_data) { - int i; - char **old_refs = NULL; + return strcmp((const char *)list_data, (const char *) user_data); +} - if ((filter == NULL) || (name == NULL)) +int append_filter_ref(struct acl_filter *filter, char *name) +{ + if (filter == NULL || name == NULL) return 0; - for (i = 0; i < filter->ref_ct; i++) - if (STREQC(filter->refs[i], name)) - return 0; /* already exists */ - - old_refs = filter->refs; - - filter->refs = malloc((filter->ref_ct + 1) * sizeof(char *)); + if (filter->refs == NULL) + filter->refs = list_new(free, filter_ref_cmp); - if (filter->refs == NULL) { - CU_DEBUG("Failed to allocate memory for new ref"); - filter->refs = old_refs; - return 0; + if (list_find(filter->refs, name) != NULL) { + free(name); + return 0; /* already exists */ } - memcpy(filter->refs, old_refs, filter->ref_ct * sizeof(char *)); - - filter->refs[filter->ref_ct] = name; - filter->ref_ct++; - - free(old_refs); + list_append(filter->refs, name); return 1; } int remove_filter_ref(struct acl_filter *filter, const char *name) { - int i; - char **old_refs = NULL; - - if ((filter == NULL) || (name == NULL)) + if (filter == NULL || filter->refs == NULL || name == NULL) return 0; - /* TODO: called infrequently, but needs optimization */ - old_refs = filter->refs; - filter->ref_ct = 0; - - for (i = 0; i < filter->ref_ct; i++) { - if (STREQC(old_refs[i], name)) { - free(old_refs[i]); - } - else if(append_filter_ref(filter, old_refs[i]) == 0) { - return 0; - } - } + list_remove(filter->refs, (void *) name); return 1; } diff --git a/libxkutil/acl_parsing.h b/libxkutil/acl_parsing.h index 5b99175..e49f384 100644 --- a/libxkutil/acl_parsing.h +++ b/libxkutil/acl_parsing.h @@ -26,6 +26,8 @@ #include #include +#include "list_util.h" + struct acl_mac_rule { char *srcmacaddr; char *srcmacmask; @@ -152,8 +154,7 @@ struct acl_filter { struct acl_rule **rules; int rule_ct; - char **refs; - int ref_ct; + list_t *refs; }; void cleanup_rule(struct acl_rule *rule); diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index 9a2ada9..5c16ebe 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -28,6 +28,7 @@ #include #include "xmlgen.h" +#include "list_util.h" #ifndef TEST #include "misc_util.h" @@ -1467,12 +1468,31 @@ char *res_to_xml(struct virt_pool_res *res) { return xml; } +static bool filter_ref_foreach(void *list_data, void *user_data) +{ + char *filter = (char *) list_data; + xmlNodePtr root = (xmlNodePtr) user_data; + xmlNodePtr tmp = NULL; + + tmp = xmlNewChild(root, NULL, BAD_CAST "filterref", NULL); + if (tmp == NULL) { + CU_DEBUG("Error creating filterref node"); + return false; + } + + if (xmlNewProp(tmp, BAD_CAST "filter", BAD_CAST list_data) == NULL) { + CU_DEBUG("Error adding filter attribute '%s'", filter); + return false; + } + + return true; +} + char *filter_to_xml(struct acl_filter *filter) { char *xml = NULL; xmlNodePtr root = NULL; xmlNodePtr tmp = NULL; - int i; root = xmlNewNode(NULL, BAD_CAST "filter"); if (root == NULL) @@ -1494,12 +1514,8 @@ char *filter_to_xml(struct acl_filter *filter) goto out; } - for (i = 0; i < filter->ref_ct; i++) { - tmp = xmlNewChild(root, NULL, BAD_CAST "filterref", NULL); - if (xmlNewProp(tmp, BAD_CAST "filter", - BAD_CAST filter->refs[i]) == NULL) - goto out; - } + if (!list_foreach(filter->refs, filter_ref_foreach, (void *) root)) + goto out; xml = tree_to_xml(root); diff --git a/src/Virt_NestedFilterList.c b/src/Virt_NestedFilterList.c index 81c4408..a8565d6 100644 --- a/src/Virt_NestedFilterList.c +++ b/src/Virt_NestedFilterList.c @@ -34,6 +34,7 @@ #include "acl_parsing.h" #include "misc_util.h" +#include "list_util.h" #include "Virt_FilterList.h" static const CMPIBroker *_BROKER; @@ -120,7 +121,7 @@ static CMPIStatus parent_to_child( CMPIInstance *instance = NULL; const char * name = NULL; virConnectPtr conn = NULL; - int i; + list_node_t *head, *node; CU_DEBUG("Reference = %s", REF2STR(reference)); @@ -139,29 +140,39 @@ static CMPIStatus parent_to_child( if (parent_filter == NULL) goto out; - for (i = 0; i < parent_filter->ref_ct; i++) { - get_filter_by_name(conn, parent_filter->refs[i], - &child_filter); - if (child_filter == NULL) - continue; - - CU_DEBUG("Processing %s,", child_filter->name); - - s = instance_from_filter(_BROKER, - info->context, - reference, - child_filter, - &instance); + /* Walk refs list */ + if (parent_filter->refs == NULL) + goto end; + + head = node = list_first_node(parent_filter->refs); + if (head == NULL) + goto end; + + do { + name = (const char *) list_node_data_get(node); + get_filter_by_name(conn, name, &child_filter); + if (child_filter != NULL) { + CU_DEBUG("Processing %s,", child_filter->name); + + s = instance_from_filter(_BROKER, + info->context, + reference, + child_filter, + &instance); + + if (instance != NULL) { + CU_DEBUG("Adding instance to inst_list"); + inst_list_add(list, instance); + } - if (instance != NULL) { - CU_DEBUG("Adding instance to inst_list"); - inst_list_add(list, instance); + cleanup_filters(&child_filter, 1); } - cleanup_filters(&child_filter, 1); instance = NULL; - } + node = list_node_next_node(node); + } while (node != head); + end: cleanup_filters(&parent_filter, 1); out: @@ -183,7 +194,7 @@ static CMPIStatus child_to_parent( CMPIInstance *instance = NULL; const char *name = NULL; virConnectPtr conn = NULL; - int count, i, j; + int count, i; CU_DEBUG("Reference = %s", REF2STR(reference)); @@ -206,24 +217,20 @@ static CMPIStatus child_to_parent( /* return any filter that has name in refs */ for (i = 0; i < count; i++) { - for (j = 0; j < _list[i].ref_ct; j++) { - if (STREQC(name, _list[i].refs[j])) { - CU_DEBUG("Processing %s,", _list[i].name); + if (list_find_node(_list[i].refs, (void *) name) != NULL) { + CU_DEBUG("Processing %s,", _list[i].name); - s = instance_from_filter(_BROKER, - info->context, - reference, - &_list[i], - &instance); - - if (instance != NULL) - inst_list_add(list, instance); + s = instance_from_filter(_BROKER, + info->context, + reference, + &_list[i], + &instance); + if (instance != NULL) { + inst_list_add(list, instance); instance = NULL; } - } - } cleanup_filters(&_list, count); -- 1.7.7.6 From eblima at linux.vnet.ibm.com Tue Jan 31 21:58:42 2012 From: eblima at linux.vnet.ibm.com (Eduardo Lima (Etrunko)) Date: Tue, 31 Jan 2012 19:58:42 -0200 Subject: [Libvirt-cim] [PATCH v6 0/3] Implementation of a linked list helper Message-ID: <1328047125-22037-1-git-send-email-eblima@linux.vnet.ibm.com> From: "Eduardo Lima (Etrunko)" This series provides a generic linked list implementation for libxkutil that is based on the one originally developed for the libvirt domain events support recently integrated upstream. As test case I ported the ComputerSystemIndication provider code to use this list implementation. In the near future it will be also used by the event loop that I am currently working on to allow systems with libvirt older than 0.9.0 to make use of the same feature. Other possible use cases would be to port the code of libxkutil/*_parsing* to also use the list implementation instead of static arrays. Changes from v5: - Fix possible NULL dereference in list_first() Changes from v4: - Fix possible NULL dereference in list_last_node() - Fix possible leak in acl_parsing.c Changes from v3: - Fix crashes in list_free(), list_first_node() and list_count() - Include patch that ports the acl filter ref code to use the linked list implementation Changes from v2: - Make list struct private Changes from v1: - Fix version iformation in Makefile.am Eduardo Lima (Etrunko) (3): libxkutil: Linked list helper CSI: Use list helper implementation ACL: Use linked list helper for filter refs libxkutil/Makefile.am | 51 +++++-- libxkutil/acl_parsing.c | 58 +++------ libxkutil/acl_parsing.h | 5 +- libxkutil/list_util.c | 254 +++++++++++++++++++++++++++++++++++ libxkutil/list_util.h | 73 ++++++++++ libxkutil/xmlgen.c | 30 +++- src/Virt_ComputerSystemIndication.c | 95 ++++---------- src/Virt_NestedFilterList.c | 73 ++++++----- 8 files changed, 472 insertions(+), 167 deletions(-) create mode 100644 libxkutil/list_util.c create mode 100644 libxkutil/list_util.h -- 1.7.7.6