MOD aaa-12 桥模型代码上传
SOL 桥模型代码上传 修改人:zhangliang 检视人:zhangliang
This commit is contained in:
parent
b4b892cee7
commit
afb3e3296a
|
@ -0,0 +1,641 @@
|
|||
#ifndef _LINUX_LIST_H
|
||||
#define _LINUX_LIST_H
|
||||
|
||||
#define container_of(ptr,type,member) ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
||||
|
||||
|
||||
//#if defined(__KERNEL__) || defined(_LVM_H_INCLUDE)
|
||||
|
||||
//#include <linux/prefetch.h>
|
||||
|
||||
/*
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
|
||||
typedef struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
} list_t;
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
#define INIT_LIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
|
||||
static void inline prefetch(void *p){}
|
||||
|
||||
static inline void __list_add(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static inline void list_add(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_del(struct list_head *prev, struct list_head *next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
* Note: list_empty on entry does not return true after this, the entry is in an undefined state.
|
||||
*/
|
||||
static inline void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
entry->next = (void *) 0;
|
||||
entry->prev = (void *) 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_replace - replace old entry by new one
|
||||
* @old : the element to be replaced
|
||||
* @new : the new element to insert
|
||||
*
|
||||
* If @old was empty, it will be overwritten.
|
||||
*/
|
||||
static inline void list_replace(struct list_head *old,
|
||||
struct list_head *new)
|
||||
{
|
||||
new->next = old->next;
|
||||
new->next->prev = new;
|
||||
new->prev = old->prev;
|
||||
new->prev->next = new;
|
||||
}
|
||||
|
||||
static inline void list_replace_init(struct list_head *old,
|
||||
struct list_head *new)
|
||||
{
|
||||
list_replace(old, new);
|
||||
INIT_LIST_HEAD(old);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
*/
|
||||
static inline void list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move - delete from one list and add as another's head
|
||||
* @list: the entry to move
|
||||
* @head: the head that will precede our entry
|
||||
*/
|
||||
static inline void list_move(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move_tail - delete from one list and add as another's tail
|
||||
* @list: the entry to move
|
||||
* @head: the head that will follow our entry
|
||||
*/
|
||||
static inline void list_move_tail(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add_tail(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static inline int list_empty(const struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
static inline void __list_splice(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static inline void list_splice(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list))
|
||||
__list_splice(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice_init - join two lists and reinitialise the emptied list.
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*
|
||||
* The list at @list is reinitialised
|
||||
*/
|
||||
static inline void list_splice_init(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list)) {
|
||||
__list_splice(list, head);
|
||||
INIT_LIST_HEAD(list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
/**
|
||||
* list_first_entry - get the first element from a list
|
||||
* @ptr: the list head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Note, that list is expected to be not empty.
|
||||
*/
|
||||
#define list_first_entry(ptr, type, member) \
|
||||
list_entry((ptr)->next, type, member)
|
||||
|
||||
/**
|
||||
* list_last_entry - get the last element from a list
|
||||
* @ptr: the list head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Note, that list is expected to be not empty.
|
||||
*/
|
||||
#define list_last_entry(ptr, type, member) \
|
||||
list_entry((ptr)->prev, type, member)
|
||||
|
||||
/**
|
||||
* list_first_entry_or_null - get the first element from a list
|
||||
* @ptr: the list head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Note that if the list is empty, it returns NULL.
|
||||
*/
|
||||
#define list_first_entry_or_null(ptr, type, member) \
|
||||
(!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
|
||||
|
||||
/**
|
||||
* list_next_entry - get the next element in list
|
||||
* @pos: the type * to cursor
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_next_entry(pos, member) \
|
||||
list_entry((pos)->member.next, typeof(*(pos)), member)
|
||||
|
||||
/**
|
||||
* list_prev_entry - get the prev element in list
|
||||
* @pos: the type * to cursor
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_prev_entry(pos, member) \
|
||||
list_entry((pos)->member.prev, typeof(*(pos)), member)
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_prev - iterate over a list backwards
|
||||
* @pos: the &struct list_head to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_prev(pos, head) \
|
||||
for (pos = (head)->prev; pos != (head); pos = pos->prev)
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate over a list safe against removal of list entry
|
||||
* @pos: the &struct list_head to use as a loop cursor.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
|
||||
* @pos: the &struct list_head to use as a loop cursor.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_prev_safe(pos, n, head) \
|
||||
for (pos = (head)->prev, n = pos->prev; \
|
||||
pos != (head); \
|
||||
pos = n, n = pos->prev)
|
||||
|
||||
/**
|
||||
* list_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_for_each_entry(pos, head, member) \
|
||||
for (pos = list_first_entry(head, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_next_entry(pos, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_reverse - iterate backwards over list of given type.
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_reverse(pos, head, member) \
|
||||
for (pos = list_last_entry(head, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_prev_entry(pos, member))
|
||||
|
||||
/**
|
||||
* list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
|
||||
* @pos: the type * to use as a start point
|
||||
* @head: the head of the list
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Prepares a pos entry for use as a start point in list_for_each_entry_continue().
|
||||
*/
|
||||
#define list_prepare_entry(pos, head, member) \
|
||||
((pos) ? : list_entry(head, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_continue - continue iteration over list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Continue to iterate over list of given type, continuing after
|
||||
* the current position.
|
||||
*/
|
||||
#define list_for_each_entry_continue(pos, head, member) \
|
||||
for (pos = list_next_entry(pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_next_entry(pos, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_continue_reverse - iterate backwards from the given point
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Start to iterate over list of given type backwards, continuing after
|
||||
* the current position.
|
||||
*/
|
||||
#define list_for_each_entry_continue_reverse(pos, head, member) \
|
||||
for (pos = list_prev_entry(pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_prev_entry(pos, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_from - iterate over list of given type from the current point
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Iterate over list of given type, continuing from current position.
|
||||
*/
|
||||
#define list_for_each_entry_from(pos, head, member) \
|
||||
for (; &pos->member != (head); \
|
||||
pos = list_next_entry(pos, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe(pos, n, head, member) \
|
||||
for (pos = list_first_entry(head, typeof(*pos), member), \
|
||||
n = list_next_entry(pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_next_entry(n, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe_continue - continue list iteration safe against removal
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Iterate over list of given type, continuing after current point,
|
||||
* safe against removal of list entry.
|
||||
*/
|
||||
#define list_for_each_entry_safe_continue(pos, n, head, member) \
|
||||
for (pos = list_next_entry(pos, member), \
|
||||
n = list_next_entry(pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_next_entry(n, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe_from - iterate over list from current point safe against removal
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Iterate over list of given type from current point, safe against
|
||||
* removal of list entry.
|
||||
*/
|
||||
#define list_for_each_entry_safe_from(pos, n, head, member) \
|
||||
for (n = list_next_entry(pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_next_entry(n, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Iterate backwards over list of given type, safe against removal
|
||||
* of list entry.
|
||||
*/
|
||||
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
|
||||
for (pos = list_last_entry(head, typeof(*pos), member), \
|
||||
n = list_prev_entry(pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_prev_entry(n, member))
|
||||
|
||||
/**
|
||||
* list_safe_reset_next - reset a stale list_for_each_entry_safe loop
|
||||
* @pos: the loop cursor used in the list_for_each_entry_safe loop
|
||||
* @n: temporary storage used in list_for_each_entry_safe
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* list_safe_reset_next is not safe to use in general if the list may be
|
||||
* modified concurrently (eg. the lock is dropped in the loop body). An
|
||||
* exception to this is if the cursor element (pos) is pinned in the list,
|
||||
* and list_safe_reset_next is called after re-taking the lock and before
|
||||
* completing the current iteration of the loop body.
|
||||
*/
|
||||
#define list_safe_reset_next(pos, n, member) \
|
||||
n = list_next_entry(pos, member)
|
||||
|
||||
|
||||
/*
|
||||
* Double linked lists with a single pointer list head.
|
||||
* Mostly useful for hash tables where the two pointer list head is
|
||||
* too wasteful.
|
||||
* You lose the ability to access the tail in O(1).
|
||||
*/
|
||||
#define LIST_POISON1 NULL
|
||||
#define LIST_POISON2 NULL
|
||||
|
||||
#define READ_ONCE(x) (x)
|
||||
#define WRITE_ONCE(x, val) x=(val)
|
||||
|
||||
|
||||
struct hlist_head {
|
||||
struct hlist_node *first;
|
||||
};
|
||||
|
||||
struct hlist_node {
|
||||
struct hlist_node *next, **pprev;
|
||||
};
|
||||
|
||||
#define HLIST_HEAD_INIT { .first = NULL }
|
||||
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
|
||||
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
|
||||
static inline void INIT_HLIST_NODE(struct hlist_node *h)
|
||||
{
|
||||
h->next = NULL;
|
||||
h->pprev = NULL;
|
||||
}
|
||||
|
||||
static inline int hlist_unhashed(const struct hlist_node *h)
|
||||
{
|
||||
return !h->pprev;
|
||||
}
|
||||
|
||||
static inline int hlist_empty(const struct hlist_head *h)
|
||||
{
|
||||
return !READ_ONCE(h->first);
|
||||
}
|
||||
|
||||
static inline void __hlist_del(struct hlist_node *n)
|
||||
{
|
||||
struct hlist_node *next = n->next;
|
||||
struct hlist_node **pprev = n->pprev;
|
||||
|
||||
WRITE_ONCE(*pprev, next);
|
||||
if (next)
|
||||
next->pprev = pprev;
|
||||
}
|
||||
|
||||
static inline void hlist_del(struct hlist_node *n)
|
||||
{
|
||||
__hlist_del(n);
|
||||
n->next = LIST_POISON1;
|
||||
n->pprev = LIST_POISON2;
|
||||
}
|
||||
|
||||
static inline void hlist_del_init(struct hlist_node *n)
|
||||
{
|
||||
if (!hlist_unhashed(n)) {
|
||||
__hlist_del(n);
|
||||
INIT_HLIST_NODE(n);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
|
||||
{
|
||||
struct hlist_node *first = h->first;
|
||||
n->next = first;
|
||||
if (first)
|
||||
first->pprev = &n->next;
|
||||
WRITE_ONCE(h->first, n);
|
||||
n->pprev = &h->first;
|
||||
}
|
||||
|
||||
/* next must be != NULL */
|
||||
static inline void hlist_add_before(struct hlist_node *n,
|
||||
struct hlist_node *next)
|
||||
{
|
||||
n->pprev = next->pprev;
|
||||
n->next = next;
|
||||
next->pprev = &n->next;
|
||||
WRITE_ONCE(*(n->pprev), n);
|
||||
}
|
||||
|
||||
static inline void hlist_add_behind(struct hlist_node *n,
|
||||
struct hlist_node *prev)
|
||||
{
|
||||
n->next = prev->next;
|
||||
WRITE_ONCE(prev->next, n);
|
||||
n->pprev = &prev->next;
|
||||
|
||||
if (n->next)
|
||||
n->next->pprev = &n->next;
|
||||
}
|
||||
|
||||
/* after that we'll appear to be on some hlist and hlist_del will work */
|
||||
static inline void hlist_add_fake(struct hlist_node *n)
|
||||
{
|
||||
n->pprev = &n->next;
|
||||
}
|
||||
|
||||
static inline int hlist_fake(struct hlist_node *h)
|
||||
{
|
||||
return h->pprev == &h->next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the node is the only node of the head without
|
||||
* accessing head:
|
||||
*/
|
||||
static inline int
|
||||
hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h)
|
||||
{
|
||||
return !n->next && n->pprev == &h->first;
|
||||
}
|
||||
|
||||
/*
|
||||
* Move a list from one list head to another. Fixup the pprev
|
||||
* reference of the first entry if it exists.
|
||||
*/
|
||||
static inline void hlist_move_list(struct hlist_head *old,
|
||||
struct hlist_head *new)
|
||||
{
|
||||
new->first = old->first;
|
||||
if (new->first)
|
||||
new->first->pprev = &new->first;
|
||||
old->first = NULL;
|
||||
}
|
||||
|
||||
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
|
||||
|
||||
#define hlist_for_each(pos, head) \
|
||||
for (pos = (head)->first; pos ; pos = pos->next)
|
||||
|
||||
#define hlist_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
|
||||
pos = n)
|
||||
|
||||
#define hlist_entry_safe(ptr, type, member) \
|
||||
({ typeof(ptr) ____ptr = (ptr); \
|
||||
____ptr ? hlist_entry(____ptr, type, member) : NULL; \
|
||||
})
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry(pos, head, member) \
|
||||
for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
|
||||
pos; \
|
||||
pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_continue - iterate over a hlist continuing after current point
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry_continue(pos, member) \
|
||||
for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member);\
|
||||
pos; \
|
||||
pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_from - iterate over a hlist continuing from current point
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry_from(pos, member) \
|
||||
for (; pos; \
|
||||
pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another &struct hlist_node to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry_safe(pos, n, head, member) \
|
||||
for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\
|
||||
pos && ({ n = pos->member.next; 1; }); \
|
||||
pos = hlist_entry_safe(n, typeof(*pos), member))
|
||||
|
||||
|
||||
#endif
|
|
@ -36,6 +36,8 @@ typedef enum {
|
|||
RET_NOTSUPPORT = 11,
|
||||
RET_INPUTERR = 12,
|
||||
RET_IPINVALID = 13,
|
||||
RET_BR_INVALID = 14,
|
||||
RET_EXIST = 15,
|
||||
} ret_code;
|
||||
|
||||
#define RET_ERROR_DISC \
|
||||
|
@ -53,7 +55,9 @@ typedef enum {
|
|||
{ RET_SOCKERR, "SockError"},\
|
||||
{ RET_NOTSUPPORT, "NotSupport"},\
|
||||
{ RET_INPUTERR, "InputError"},\
|
||||
{ RET_IPINVALID, "IpInvalid"}\
|
||||
{ RET_IPINVALID, "IpInvalid"},\
|
||||
{ RET_BR_INVALID, "BrNameInvalid"},
|
||||
{ RET_EXIST, "AlreadyExist"}\
|
||||
}
|
||||
|
||||
#define RET_BUFF_SIZE 256;
|
||||
|
|
|
@ -75,6 +75,16 @@ do { \
|
|||
}\
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_PTR_RET(ptr) \
|
||||
do { \
|
||||
if (ptr == NULL) \
|
||||
{\
|
||||
rpc_log_error("ret error: %s\n", rpc_code_format(RET_NULLP));\
|
||||
return RET_NULLP;\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
|
||||
#define ASSERT_RET_VOID(ret) \
|
||||
do { \
|
||||
if (ret != RET_OK) \
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
#ifndef BRCONFIG_H_
|
||||
#define BRCONFIG_H_
|
||||
|
||||
#define BR_NAMSIZ INTERFACE_NAMSIZ
|
||||
#define MAC_STRSIZ 32
|
||||
#define LOCAL_STRSIZ 16
|
||||
#define TIME_STRSIZ 16
|
||||
#define MAC_MAXIZS 1024
|
||||
#define FDB_CHUNK 128
|
||||
|
||||
typedef enum {
|
||||
BR_CREATE_EVENT = 1,
|
||||
BR_DELETE_EVENT,
|
||||
BR_IF_JOIN_EVENT,
|
||||
BR_IF_LEAVE_EVENT,
|
||||
BR_EVENT_INVALID
|
||||
} BR_EVENT_TYPE;
|
||||
|
||||
typedef int (*BR_EVENT_FUNC)(BR_EVENT_TYPE event_type, br_event_t event_arg);
|
||||
|
||||
/************************************************************/
|
||||
/* 结构体 */
|
||||
/************************************************************/
|
||||
/* 事件通知数据结构 */
|
||||
struct _br_event {
|
||||
char *br_name;
|
||||
char *if_name;
|
||||
};
|
||||
typedef struct _br_event br_event_t;
|
||||
|
||||
struct _br_event_node {
|
||||
struct hlist_node list;
|
||||
BR_EVENT_TYPE br_event;
|
||||
BR_EVENT_FUNC event_func;
|
||||
};
|
||||
typedef struct _br_event_node br_event_node_t;
|
||||
|
||||
struct _br_event_head {
|
||||
struct hlist_head head;
|
||||
pthread_mutex_t lock;
|
||||
boolean init;
|
||||
};
|
||||
typedef struct _br_event_head br_event_head_t;
|
||||
|
||||
|
||||
/* 临时数据结构 */
|
||||
struct _brif_temp {
|
||||
int index;
|
||||
char *if_list;
|
||||
};
|
||||
typedef struct _brif_temp br_if_temp_t;
|
||||
|
||||
struct _br_temp {
|
||||
char *br_name;
|
||||
boolean result;
|
||||
};
|
||||
typedef struct _br_temp br_temp_t;
|
||||
|
||||
/* 配置消息数据结构 */
|
||||
struct _br_config {
|
||||
char br_name[BR_NAMSIZ];
|
||||
int port_num;
|
||||
char *ports;
|
||||
};
|
||||
typedef struct _br_config br_config_t;
|
||||
|
||||
struct _br_fdb_config {
|
||||
char br_name[BR_NAMSIZ];
|
||||
};
|
||||
typedef struct _br_fdb_config br_fdb_config_t;
|
||||
|
||||
/* json解析数据结构 */
|
||||
struct _br_config_string {
|
||||
int config_type;
|
||||
char br_name[BR_NAMSIZ];
|
||||
};
|
||||
typedef struct _br_config_string br_config_string_t;
|
||||
|
||||
struct _br_if_config_string {
|
||||
int config_type;
|
||||
char br_name[BR_NAMSIZ];
|
||||
char *ports;
|
||||
};
|
||||
typedef struct _br_if_config_string br_if_config_string_t;
|
||||
|
||||
struct _br_fdb_string{
|
||||
int config_type;
|
||||
char br_name[BR_NAMSIZ];
|
||||
};
|
||||
typedef struct _br_fdb_string br_fdb_string_t;
|
||||
|
||||
/* 状态数据结构 */
|
||||
struct _br_fdb_info{
|
||||
char mac_addr[MAC_STRSIZ];
|
||||
char port[INTERFACE_NAMSIZ];
|
||||
char local[LOCAL_STRSIZ];
|
||||
char time[TIME_STRSIZ];
|
||||
};
|
||||
typedef struct _br_fdb_info fdb_info_t;
|
||||
|
||||
struct _br_fdb_status{
|
||||
char br_name[BR_NAMSIZ];
|
||||
int fdb_num;
|
||||
fdb_info_t fdb_info[MAC_MAXIZS];
|
||||
};
|
||||
typedef struct _br_fdb_status br_fdb_status_t;
|
||||
|
||||
/* **********************************************************/
|
||||
/* 提供给其他模块调用的函数 */
|
||||
/************************************************************/
|
||||
|
||||
/* 通过接口名获取所在桥名 */
|
||||
int br_if_bridge_get(char *port_name , char *br_name);
|
||||
|
||||
/* 向桥中添加接口 */
|
||||
ret_code br_if_bridge_add(char *br_name, char *port_list,
|
||||
int cnt, int *sys_err);
|
||||
|
||||
/* 删除桥中的接口 */
|
||||
ret_code br_if_bridge_del(char *br_name, char *port_list,
|
||||
int cnt, int *sys_err);
|
||||
|
||||
/* 获取桥中接口数量 */
|
||||
int br_if_bridge_num(char *br_name);
|
||||
|
||||
/* **********************************************************/
|
||||
/* 配置管理注册函数 */
|
||||
/************************************************************/
|
||||
|
||||
/* 桥配置 */
|
||||
ret_code br_config_chk(uint source,uint *config_type,
|
||||
pointer input, int *input_len,
|
||||
pointer output, int *output_len);
|
||||
|
||||
ret_code br_config_proc(uint source, uint config_type,
|
||||
pointer input, int input_len,
|
||||
pointer output, int *output_len);
|
||||
/* 桥接口配置 */
|
||||
ret_code br_if_config_chk(uint source,uint *config_type,
|
||||
pointer input, int *input_len,
|
||||
pointer output, int *output_len);
|
||||
|
||||
ret_code br_if_config_proc(uint source, uint config_type,
|
||||
pointer input, int input_len,
|
||||
pointer output, int *output_len);
|
||||
|
||||
ret_code br_if_config_get(uint source,
|
||||
pointer input, int input_len,
|
||||
pointer output, int *output_len);
|
||||
|
||||
ret_code br_if_config_get_all(uint source,
|
||||
pointer output, int *output_len);
|
||||
/* 桥fdb配置 */
|
||||
ret_code br_fdb_config_chk(uint source,uint *config_type,
|
||||
pointer input, int *input_len,
|
||||
pointer output, int *output_len);
|
||||
|
||||
ret_code br_fdb_config_get(uint source,
|
||||
pointer input, int input_len,
|
||||
pointer output, int *output_len);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,925 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "configm.h"
|
||||
#include "brconfig.h"
|
||||
#include "rpc.h"
|
||||
#include "parsefile.h"
|
||||
#include "libbridge.h"
|
||||
#include "brnetlink.h"
|
||||
#include "list.h"
|
||||
|
||||
#ifndef DESC("事件通知函数")
|
||||
struct br_event_head_t br_event_tbl = {.lock = 0, .init = false};
|
||||
|
||||
int br_invoke_event(BR_EVENT_TYPE event_type, br_event_t event_arg)
|
||||
{
|
||||
br_event_node_t *hnode;
|
||||
|
||||
pthread_mutex_lock(&(br_event_tbl.lock));
|
||||
hlist_for_each_entry(hnode, &(br_event_tbl.head), list)
|
||||
{
|
||||
if(hnode->br_event == event_type)
|
||||
{
|
||||
hnode->event_func(event_type, event_arg);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&(br_event_tbl.lock));
|
||||
}
|
||||
|
||||
|
||||
int br_event_register(BR_EVENT_TYPE event_type, BR_EVENT_FUNC event_func)
|
||||
{
|
||||
br_event_node_t *hnode = NULL;
|
||||
|
||||
if(br_event_tbl.init == false)
|
||||
{ INIT_HLIST_HEAD(&(br_event_tbl.head);
|
||||
pthread_mutex_init(&(br_event_tbl.lock), NULL);
|
||||
br_event_tbl.init = true;
|
||||
}
|
||||
|
||||
hnode = (br_event_node_t *)rpc_new0(br_event_node_t, 1);
|
||||
if(!hnode)
|
||||
{
|
||||
rpc_log_error("br_event_register failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
INIT_HLIST_NODE(&hnode->list);
|
||||
hnode->br_event = event_type;
|
||||
hnode->event_func = event_func;
|
||||
|
||||
pthread_mutex_lock(&(br_event_tbl.lock));
|
||||
hlist_add_head(&hnode->list, &(br_event_tbl.head));
|
||||
pthread_mutex_unlock(&(br_event_tbl.lock));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int br_event_unregister(BR_EVENT_TYPE event_type, BR_EVENT_FUNC event_func)
|
||||
{
|
||||
br_event_node_t *hnode = NULL;
|
||||
struct hlist_node *n;
|
||||
|
||||
if(br_event_tbl.init == false)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&(br_event_tbl.lock));
|
||||
hlist_for_each_entry_safe(hnode, n, &(br_event_tbl.head), list)
|
||||
{
|
||||
if(event_type == hnode->br_event &&
|
||||
event_func == hnode->event_func)
|
||||
{
|
||||
hlist_del(&hnode->list);
|
||||
rpc_free(hnode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&(br_event_tbl.lock));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifndef DESC("桥配置辅助函数")
|
||||
int br_copy_port_name(const char *b, const char *p, void *arg)
|
||||
{
|
||||
br_if_temp_t *br_if = (br_if_temp_t *)arg;
|
||||
char *dst_ptr = NULL;
|
||||
|
||||
br_if->if_list = realloc(br_if->if_list, INTERFACE_NAMSIZ);
|
||||
ASSERT_PTR_RET(br_if->if_list);
|
||||
|
||||
dst_ptr = br_if->if_list + br_if->index * INTERFACE_NAMSIZ
|
||||
strncpy(dst_ptr, p, INTERFACE_NAMSIZ - 1);
|
||||
|
||||
br_if->index++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret_code br_name_chk(char *br_name)
|
||||
{
|
||||
if(strlen(br_name) == 0
|
||||
|| strlen(br_name) > BR_NAMSIZ - 1
|
||||
|| strstr(br_name, "br-vl") != NULL)
|
||||
{
|
||||
return RET_BR_INVALID;
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
int br_name_cmp(char *br_name, void *args)
|
||||
{
|
||||
br_temp_t *cmp_args = (br_temp_t *)args;
|
||||
|
||||
if(strcmp(br_name, cmp_args->br_name) == 0)
|
||||
{
|
||||
cmp_args->result = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
boolean br_is_exist(char *br_name)
|
||||
{
|
||||
br_temp_t cmp_args = {br_name, false};
|
||||
|
||||
br_foreach_bridge(br_name_cmp, &cmp_args);
|
||||
|
||||
return cmp_args.result;
|
||||
}
|
||||
|
||||
|
||||
ret_code br_if_bridge_get(char *port_name, char* br_name)
|
||||
{
|
||||
char bridge_name[BR_NAMSIZ] = {0};
|
||||
|
||||
if(get_br_from_port(port_name, bridge_name) == RET_OK)
|
||||
{
|
||||
if(br_name)
|
||||
{
|
||||
strncpy(br_name, bridge_name, BR_NAMSIZ - 1);
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
return RET_NOTFOUND;
|
||||
}
|
||||
|
||||
ret_code br_if_bridge_check(char *port_list, int cnt, uint config_type)
|
||||
{
|
||||
char *ptr_name = NULL;
|
||||
int i;
|
||||
|
||||
for(i = 0; i< cnt; i++)
|
||||
{
|
||||
ptr_name = port_list + INTERFACE_NAMSIZ * i;
|
||||
if (if_nametoindex(ptr_name) == 0)
|
||||
{
|
||||
return RET_NOTFOUND;
|
||||
}
|
||||
|
||||
if(br_if_bridge_get(ptr_name, NULL) == RET_OK)
|
||||
{
|
||||
if(config_type == CM_CONFIG_ADD)
|
||||
{
|
||||
return RET_EXIST;
|
||||
}
|
||||
}
|
||||
else if(config_type == CM_CONFIG_DEL)
|
||||
{
|
||||
return RET_NOTFOUND;
|
||||
}
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
ret_code br_if_bridge_add(char * br_name, char *port_list, int cnt, int *sys_err)
|
||||
{
|
||||
ret_code ret = RET_OK;
|
||||
char *port_name;
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < cnt)
|
||||
{
|
||||
port_name = port_list + INTERFACE_NAMSIZ * i;
|
||||
err = br_add_interface(br_name, port_name);
|
||||
if(err != 0)
|
||||
{
|
||||
sys_err = err;
|
||||
ret = RET_SYSERR;
|
||||
continue;
|
||||
}
|
||||
|
||||
br_event_t event_arg = {br_name, port_name};
|
||||
br_invoke_event(BR_IF_JOIN_EVENT, event_arg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret_code br_if_bridge_del(char * br_name, char *port_list, int cnt, int *sys_err)
|
||||
{
|
||||
ret_code ret = RET_OK;
|
||||
char *port_name;
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < cnt)
|
||||
{
|
||||
port_name = port_list + INTERFACE_NAMSIZ * i;
|
||||
err = br_del_interface(br_name, port_name);
|
||||
if(err != 0)
|
||||
{
|
||||
sys_err = err;
|
||||
ret = RET_SYSERR;
|
||||
continue;
|
||||
}
|
||||
|
||||
br_event_t event_arg = {br_name, port_name};
|
||||
br_invoke_event(BR_IF_LEAVE_EVENT, event_arg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int br_if_bridge_num(char *br_name)
|
||||
{
|
||||
int cnt = 0;
|
||||
|
||||
err = br_for_port_num(br_name, &cnt);
|
||||
cnt = (err != 0) ? 0 : cnt;
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef DESC("桥配置json格式转换函数")
|
||||
|
||||
ret_code br_config_json_parse(pointer input, uint *conf_type, char *br_name)
|
||||
{
|
||||
cJSON *json_obj;
|
||||
|
||||
json_obj = cJSON_Parse(input);
|
||||
ASSERT_PTR_RET(json_obj);
|
||||
|
||||
rpc_log_info("json input:\n %s\n", cJSON_Print(json_obj));
|
||||
|
||||
s2j_create_struct_obj(br_config, br_config_string_t);
|
||||
|
||||
if(br_config == NULL)
|
||||
{
|
||||
cJSON_Delete(json_obj);
|
||||
return RET_NOMEM;
|
||||
}
|
||||
|
||||
s2j_struct_get_basic_element(br_config, json_obj, int, config_type);
|
||||
s2j_struct_get_string_element(br_config, json_obj, br_name, BR_NAMSIZ);
|
||||
|
||||
strncpy(br_name, br_config->br_name, BR_NAMSIZ - 1);
|
||||
*conf_type = br_config->config_type;
|
||||
|
||||
s2j_delete_struct_obj(br_config);
|
||||
cJSON_Delete(json_obj);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
int br_json_to_string( cJSON *json_obj, pointer output)
|
||||
{
|
||||
char *json_str;
|
||||
int output_len = 0;
|
||||
|
||||
if(json_obj == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
json_str = cJSON_PrintUnformatted(json_array);
|
||||
output_len = strlen(json_str) + 1;
|
||||
|
||||
if(output_len > CM_BUFF_SIZE)
|
||||
{
|
||||
rpc_log_warn("output len is too long %d, cut off!", output_len);
|
||||
json_str[CM_BUFF_SIZE - 1] = '\0';
|
||||
output_len = CM_BUFF_SIZE;
|
||||
}
|
||||
|
||||
memcpy(output, json_str, output_len);
|
||||
|
||||
rpc_free(json_str);
|
||||
s2j_delete_json_obj(json_obj);
|
||||
|
||||
return output_len;
|
||||
}
|
||||
|
||||
cJSON *br_config_format_json(br_config_t *br_config)
|
||||
{
|
||||
cJSON *json_obj;
|
||||
|
||||
s2j_create_json_obj(json_obj);
|
||||
if(json_obj == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s2j_json_set_basic_element(json_obj, br_config, string, br_name);
|
||||
s2j_json_set_array_element(json_obj, br_config, string,
|
||||
ports, br_config->port_num);
|
||||
|
||||
return json_obj;
|
||||
}
|
||||
|
||||
ret_code br_bridge_info( char *br_name, cJSON *json_obj, int *err)
|
||||
{
|
||||
ret_code ret = RET_OK;
|
||||
br_if_temp_t br_if = {0};
|
||||
br_config_t br_config = {0};
|
||||
|
||||
br_if.index = 0;
|
||||
br_if.if_list = NULL;
|
||||
|
||||
*err = br_foreach_port(br_name, br_copy_port_name, &br_if)
|
||||
if (*err >= 0)
|
||||
{
|
||||
strncpy(br_config.br_name, br_name, BR_NAMSIZ - 1);
|
||||
br_config.ports = br_if.if_list;
|
||||
br_config.port_num = br_if.index;
|
||||
json_obj = br_config_format_json(&br_config);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = RET_SYSERR;
|
||||
}
|
||||
|
||||
if(br_if.if_list)
|
||||
{
|
||||
rpc_free(br_if.if_list);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int br_bridge_info_each(const char *br_name, void *args)
|
||||
{
|
||||
cJSON *json_array = (cJSON *)args;
|
||||
cJSON *json_obj = NULL;
|
||||
ret_code ret = RET_OK;
|
||||
int err = 0;
|
||||
|
||||
ret = br_bridge_info(br_name, json_obj, &err);
|
||||
|
||||
if(json_obj)
|
||||
{
|
||||
cJSON_AddItemToArray(json_array, json_obj);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret_code br_if_config_json_parse(pointer input, uint *conf_type, br_config_t *br_if)
|
||||
{
|
||||
cJSON *json_obj;
|
||||
int port_num = 0;
|
||||
|
||||
json_obj = cJSON_Parse(input);
|
||||
ASSERT_PTR_RET(json_obj);
|
||||
|
||||
rpc_log_info("json input:\n %s\n", cJSON_Print(json_obj));
|
||||
|
||||
s2j_create_struct_obj(br_if_conf, br_if_config_string_t);
|
||||
|
||||
if(br_if_conf == NULL)
|
||||
{
|
||||
cJSON_Delete(json_obj);
|
||||
return RET_NOMEM;
|
||||
}
|
||||
|
||||
s2j_struct_get_basic_element(br_if_conf, json_obj, int, config_type);
|
||||
*conf_type = br_if_conf->config_type;
|
||||
|
||||
if(br_if_conf->config_type != CM_CONFIG_GET_ALL)
|
||||
{
|
||||
s2j_struct_get_string_element(br_if_conf, json_obj, string, br_name, BR_NAMSIZ);
|
||||
strncpy(br_if->br_name, br_if_conf->br_name, BR_NAMSIZ - 1);
|
||||
}
|
||||
|
||||
if(br_if_conf->config_type == CM_CONFIG_ADD
|
||||
|| br_if_conf->config_type == CM_CONFIG_DEL)
|
||||
{
|
||||
s2j_struct_get_array_string_n(br_if_conf, json_obj, string,
|
||||
ports, port_num, INTERFACE_NAMSIZ);
|
||||
br_if->port_num = port_num;
|
||||
br_if->ports = br_if_conf->ports; /*指针赋值,后续需要对该指针进行内存释放*/
|
||||
br_if_conf->ports = NULL;
|
||||
}
|
||||
|
||||
s2j_delete_struct_obj(br_if_conf);
|
||||
cJSON_Delete(json_obj);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef DESC("桥配置钩子函数")
|
||||
ret_code br_config_chk(uint source,uint *config_type,
|
||||
pointer input, int *input_len,
|
||||
pointer output, int *output_len)
|
||||
{
|
||||
int config_len = 0;
|
||||
uint conf_type = CM_CONFIG_GET;
|
||||
char br_name[BR_NAMSIZ] = {0};
|
||||
ret_code ret = RET_OK;
|
||||
int code = 0;
|
||||
|
||||
br_config_json_parse(input, &conf_type, br_name);
|
||||
config_len = strlen(br_name) + 1;
|
||||
|
||||
switch (conf_type)
|
||||
{
|
||||
case CM_CONFIG_ADD:
|
||||
case CM_CONFIG_DEL:
|
||||
case CM_CONFIG_GET:
|
||||
ret = br_name_chk(br_name);
|
||||
break;
|
||||
case CM_CONFIG_GET_ALL:
|
||||
break;
|
||||
default:
|
||||
ret = RET_NOTSUPPORT;
|
||||
}
|
||||
|
||||
/* 将传入的json数据转换成结构体,便于后续处理 */
|
||||
if(config_len <= CM_BUFF_SIZE)
|
||||
{
|
||||
memset(input, 0, *input_len);
|
||||
memcpy(input, br_name, config_len);
|
||||
*config_type = conf_type;
|
||||
*input_len = config_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = RET_NOMEM;
|
||||
}
|
||||
|
||||
RET_ERR_FORMART(ret, code, output, *output_len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret_code br_config_proc(uint source, uint config_type,
|
||||
pointer input, int input_len,
|
||||
pointer output, int *output_len)
|
||||
{
|
||||
BR_EVENT_TYPE event_type = BR_EVENT_INVALID;
|
||||
ret_code ret = RET_OK;
|
||||
int sys_ret = 0;
|
||||
char *br_name;
|
||||
|
||||
br_name = (char *)input;
|
||||
|
||||
if(config_type == CM_CONFIG_ADD)
|
||||
{
|
||||
sys_ret = br_add_bridge(br_name);
|
||||
event_type = BR_CREATE_EVENT;
|
||||
}
|
||||
else if(config_type == CM_CONFIG_DEL)
|
||||
{
|
||||
sys_ret = br_del_bridge(br_name);
|
||||
event_type = BR_DELETE_EVENT;
|
||||
}
|
||||
|
||||
if(sys_ret != 0)
|
||||
{
|
||||
ret = RET_SYSERR;
|
||||
RET_ERR_FORMART(ret, sys_ret, output, *output_len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(event_type != BR_EVENT_INVALID)
|
||||
{
|
||||
br_event_t event_arg = {br_name, NULL};
|
||||
br_invoke_event(event_type, event_arg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef DESC("桥接口配置钩子函数")
|
||||
ret_code br_if_config_chk(uint source,uint *config_type,
|
||||
pointer input, int *input_len,
|
||||
pointer output, int *output_len)
|
||||
{
|
||||
ret_code ret = RET_OK;
|
||||
br_config_t br_config = {0};
|
||||
br_config_t *temp_conf = NULL;
|
||||
int cfg_len = 0;
|
||||
|
||||
br_if_config_json_parse(input, config_type, &br_config);
|
||||
|
||||
cfg_len = BR_NAMSIZ + sizeof(br_config.port_num)
|
||||
+ br_config.port_num * INTERFACE_NAMSIZ;
|
||||
|
||||
if(cfg_len > CM_BUFF_SIZE)
|
||||
{
|
||||
ret = RET_NOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = br_name_chk(br_config.br_name);
|
||||
if(ret != RET_OK)
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if(br_is_exist(br_config.br_name) == false)
|
||||
{
|
||||
ret = RET_NOTFOUND;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if(*config_type != CM_CONFIG_ADD && *config_type != CM_CONFIG_DEL)
|
||||
{
|
||||
ret = RET_INPUTERR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = br_if_bridge_check(br_config.ports, br_config.port_num, *config_type);
|
||||
if(ret != RET_OK)
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
memset(input, 0, *input_len);
|
||||
temp_conf = (br_config_t *)input;
|
||||
|
||||
strncpy(temp_conf->br_name, br_config.br_name, BR_NAMSIZ - 1);
|
||||
temp_conf->port_num = br_config.port_num;
|
||||
memcpy(temp_conf->ports, br_config.ports, br_config.port_num * INTERFACE_NAMSIZ);
|
||||
|
||||
*input_len = cfg_len;
|
||||
|
||||
exit:
|
||||
RET_ERR_FORMART(ret, 0, output, *output_len);
|
||||
rpc_free(br_config.ports);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret_code br_if_config_proc(uint source, uint config_type,
|
||||
pointer input, int input_len,
|
||||
pointer output, int *output_len)
|
||||
{
|
||||
br_config_t *br_conf = (br_config_t *)input;
|
||||
ret_code ret = RET_OK;
|
||||
int err = 0;
|
||||
|
||||
if(config_type == CM_CONFIG_ADD)
|
||||
{
|
||||
ret = br_if_bridge_add(br_conf->br_name, br_conf->ports,
|
||||
br_conf->port_num, &err);
|
||||
}
|
||||
else if(config_type == CM_CONFIG_DEL)
|
||||
{
|
||||
ret = br_if_bridge_del(br_conf->br_name, br_conf->ports,
|
||||
br_conf->port_num, &err);
|
||||
}
|
||||
|
||||
RET_ERR_FORMART(ret, err, output, *output_len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret_code br_if_config_get(uint source,
|
||||
pointer input, int input_len,
|
||||
pointer output, int *output_len)
|
||||
{
|
||||
ret_code ret = RET_OK;
|
||||
cJSON *json_obj = NULL;
|
||||
int err = 0;
|
||||
|
||||
ret = br_bridge_info((char *)input, json_obj, &err);
|
||||
|
||||
if(ret != RET_OK)
|
||||
{
|
||||
RET_ERR_FORMART(ret, err, output, *output_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
*output_len = br_json_to_string(json_obj, output);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret_code br_if_config_get_all(uint source,
|
||||
pointer output, int *output_len)
|
||||
{
|
||||
cJSON *json_obj = NULL;
|
||||
ret_code ret = RET_OK;
|
||||
int err = 0;
|
||||
|
||||
json_obj = cJSON_CreateArray();
|
||||
if(json_obj == NULL)
|
||||
{
|
||||
ret = RET_NOMEM;
|
||||
RET_ERR_FORMART(RET_NOMEM, err, output, *output_len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(br_foreach_bridge(br_bridge_info_each, json_obj) > 0)
|
||||
{
|
||||
*output_len = br_json_to_string(json_obj, output);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef DESC("桥FDB配置辅助函数")
|
||||
|
||||
void br_format_time(const struct timeval *tv, char *str, int len)
|
||||
{
|
||||
snprintf(str, len, "%4i.%.2i", (int)tv->tv_sec, (int)tv->tv_usec/10000);
|
||||
}
|
||||
|
||||
|
||||
int br_compare_fdbs(const void *_f0, const void *_f1)
|
||||
{
|
||||
const struct fdb_entry *f0 = _f0;
|
||||
const struct fdb_entry *f1 = _f1;
|
||||
|
||||
return memcmp(f0->mac_addr, f1->mac_addr, 6);
|
||||
}
|
||||
|
||||
int br_get_if_from_portno(const char *brname, int port_no, char *ifname)
|
||||
{
|
||||
int ifindices[MAX_PORTS];
|
||||
unsigned long args[4] = { BRCTL_GET_PORT_LIST,
|
||||
(unsigned long)ifindices, MAX_PORTS, 0 };
|
||||
struct ifreq ifr;
|
||||
|
||||
if (port_no >= MAX_PORTS)
|
||||
return -1;
|
||||
|
||||
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));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(if_indextoname(ifindices[port_no], ifname) == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int br_fdb_get(char *brname, struct fdb_entry **br_fdb)
|
||||
{
|
||||
struct fdb_entry *fdb;
|
||||
int i = 0, n = 0;
|
||||
int offset = 0;
|
||||
|
||||
fdb = NULL;
|
||||
*br_fdb = NULL;
|
||||
|
||||
for(;;) {
|
||||
fdb = realloc(fdb, (offset + FDB_CHUNK) * sizeof(struct fdb_entry));
|
||||
if (!fdb) {
|
||||
rpc_log_error("Out of memory\n");
|
||||
return offset;
|
||||
}
|
||||
|
||||
*br_fdb = fdb;
|
||||
|
||||
n = br_read_fdb(brname, fdb+offset, offset, FDB_CHUNK);
|
||||
if (n == 0)
|
||||
break;
|
||||
|
||||
if (n < 0) {
|
||||
rpc_log_error( "read of forward table failed: %s\n", strerror(errno));
|
||||
return offset;
|
||||
}
|
||||
|
||||
offset += n;
|
||||
}
|
||||
|
||||
qsort(fdb, offset, sizeof(struct fdb_entry), br_compare_fdbs);
|
||||
|
||||
#if 0
|
||||
printf("port no\tmac addr\t\tis local?\tageing timer\n");
|
||||
for (i = 0; i < offset; i++) {
|
||||
const struct fdb_entry *f = fdb + i;
|
||||
printf("%3i\t", f->port_no);
|
||||
printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\t",
|
||||
f->mac_addr[0], f->mac_addr[1], f->mac_addr[2],
|
||||
f->mac_addr[3], f->mac_addr[4], f->mac_addr[5]);
|
||||
printf("%s\t\t", f->is_local?"yes":"no");
|
||||
br_show_timer(&f->ageing_timer_value);
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
return offset;
|
||||
}
|
||||
|
||||
int br_fdb_cpy(br_fdb_status_t *fdb_status, struct fdb_entry *fdb)
|
||||
{
|
||||
struct fdb_entry *temp_fdb;
|
||||
char if_name[INTERFACE_NAMSIZ];
|
||||
int i = 0;
|
||||
|
||||
for(i = 0; i < fdb_status->fdb_num && i < MAC_MAXIZS; i++)
|
||||
{
|
||||
temp_fdb = fdb + i;
|
||||
|
||||
memset(if_name, 0, INTERFACE_NAMSIZ);
|
||||
if(br_get_if_from_portno(fdb_status->br_name,
|
||||
temp_fdb->port_no,
|
||||
if_name) != 0)
|
||||
{
|
||||
rpc_log_error("port no %d can not get ifname\n", temp_fdb->port_no);
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(fdb_status->fdb_info[i].mac_addr, MAC_STRSIZ,
|
||||
"%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
temp_fdb->mac_addr[0], temp_fdb->mac_addr[1], temp_fdb->mac_addr[2],
|
||||
temp_fdb->mac_addr[3], temp_fdb->mac_addr[4], temp_fdb->mac_addr[5]);
|
||||
|
||||
strncpy(fdb_status->fdb_info[i].port, if_name, INTERFACE_NAMSIZ - 1);
|
||||
|
||||
if(temp_fdb->is_local)
|
||||
{
|
||||
strncpy(fdb_status->fdb_info[i].local, "true", LOCAL_STRSIZ - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(fdb_status->fdb_info[i].local, "false", LOCAL_STRSIZ - 1);
|
||||
}
|
||||
|
||||
br_format_time(&temp_fdb->ageing_timer_value,
|
||||
fdb_status->fdb_info[i].time, TIME_STRSIZ);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef DESC("桥FDB配置json格式转换")
|
||||
ret_code br_fdb_config_json_parse(pointer input, uint *conf_type, br_fdb_config_t *br_fdb)
|
||||
{
|
||||
cJSON *json_obj;
|
||||
int port_num = 0;
|
||||
|
||||
json_obj = cJSON_Parse(input);
|
||||
if(!json_obj)
|
||||
{
|
||||
return RET_INPUTERR;
|
||||
}
|
||||
|
||||
rpc_log_info("json input:\n %s\n", cJSON_Print(json_obj));
|
||||
|
||||
s2j_create_struct_obj(br_fdb_conf, br_fdb_string_t);
|
||||
|
||||
if(br_fdb_conf == NULL)
|
||||
{
|
||||
cJSON_Delete(json_obj);
|
||||
return RET_NOMEM;
|
||||
}
|
||||
|
||||
s2j_struct_get_string_element(br_fdb_conf, json_obj, string, br_name, BR_NAMSIZ);
|
||||
|
||||
*conf_type = br_fdb_conf->config_type;
|
||||
strncpy(br_fdb->br_name, br_fdb_conf->br_name, BR_NAMSIZ - 1);
|
||||
|
||||
s2j_delete_struct_obj(br_fdb_conf);
|
||||
cJSON_Delete(json_obj);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
ret_code br_each_fdb_to_json_string(cJSON *json_array, fdb_info_t *fdb_info)
|
||||
{
|
||||
cJSON *fdb_obj;
|
||||
|
||||
s2j_create_json_obj(fdb_obj);
|
||||
if(fdb_obj == NULL)
|
||||
{
|
||||
return RET_NOMEM;
|
||||
}
|
||||
|
||||
s2j_json_set_basic_element(fdb_obj, fdb_info, string, mac_addr);
|
||||
s2j_json_set_basic_element(fdb_obj, fdb_info, string, port);
|
||||
s2j_json_set_basic_element(fdb_obj, fdb_info, string, local);
|
||||
s2j_json_set_basic_element(fdb_obj, fdb_info, string, time);
|
||||
|
||||
cJSON_AddItemToArray(json_array, fdb_obj);
|
||||
|
||||
return RET_OK
|
||||
}
|
||||
|
||||
int br_fdb_to_json_string(br_fdb_status_t *fdb_status, char *output)
|
||||
{
|
||||
cJSON *br_obj;
|
||||
cJSON *fdb_array;
|
||||
char *json_str;
|
||||
int i;
|
||||
|
||||
s2j_create_json_obj(br_obj);
|
||||
fdb_array = cJSON_CreateArray();
|
||||
|
||||
if(br_obj == NULL || fdb_array)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
s2j_json_set_basic_element(br_obj, fdb_status, string, br_name);
|
||||
s2j_json_set_basic_element(br_obj, fdb_status, int, fdb_num);
|
||||
|
||||
for(i = 0; i < fdb_status->fdb_num; i++)
|
||||
{
|
||||
br_each_fdb_to_json_string(fdb_array, &(fdb_status->fdb_info[i]));
|
||||
}
|
||||
|
||||
cJSON_AddItemToObject(br_obj, "fdb", fdb_array);
|
||||
|
||||
br_json_to_string(br_obj, output);
|
||||
|
||||
return (strlen(output) + 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef DESC("桥FDB表配置钩子函数")
|
||||
ret_code br_fdb_config_chk(uint source,uint *config_type,
|
||||
pointer input, int *input_len,
|
||||
pointer output, int *output_len)
|
||||
{
|
||||
ret_code ret = RET_OK;
|
||||
br_fdb_config_t br_fdb = {0};
|
||||
br_fdb_config_t *temp_conf;
|
||||
int cfg_len = 0;
|
||||
|
||||
ret = br_fdb_config_json_parse(input, config_type, &br_fdb);
|
||||
if(ret != RET_OK)
|
||||
{
|
||||
RET_ERR_FORMART(ret, 0, output, *output_len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(*config_type != CM_CONFIG_GET)
|
||||
{
|
||||
ret = RET_INPUTERR;
|
||||
RET_ERR_FORMART(ret, 0, output, *output_len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* 回填解析过的数据 */
|
||||
memset(input, 0, *input_len);
|
||||
temp_conf = (br_fdb_config_t *)input;
|
||||
|
||||
strncpy(temp_conf->br_name, br_fdb.br_name, BR_NAMSIZ - 1);
|
||||
*input_len = cfg_len;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret_code br_fdb_config_get(uint source,
|
||||
pointer input, int input_len,
|
||||
pointer output, int *output_len)
|
||||
{
|
||||
br_fdb_status_t *fdb_status;
|
||||
br_fdb_config_t *br_fdb;
|
||||
struct fdb_entry *fdb;
|
||||
ret_code ret = RET_OK;
|
||||
int err = 0;
|
||||
|
||||
br_fdb = (br_fdb_config_t *)input;
|
||||
|
||||
fdb_status = (br_fdb_status_t *)rpc_new0(br_fdb_status_t, 1);
|
||||
if(fdb_status == NULL)
|
||||
{
|
||||
ret = RET_NOMEM;
|
||||
RET_ERR_FORMART(ret, 0, output, *output_len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
strncpy(fdb_status->br_name, br_fdb->br_name, BR_NAMSIZ - 1);
|
||||
fdb_status->fdb_num = br_fdb_get(br_fdb->br_name, &fdb);
|
||||
fdb_status->fdb_num = br_fdb_cpy(fdb_status, fdb);
|
||||
|
||||
*output_len = br_fdb_to_json_string(fdb_status, output);
|
||||
|
||||
rpc_free(fdb);
|
||||
rpc_free(fdb_status);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,282 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <bits/socket.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "brnetlink.h"
|
||||
|
||||
#define BR_NLMSG_TAIL(nmsg) \
|
||||
((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
|
||||
#define BR_MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
int br_seq = 0;
|
||||
int br_fd = -1;
|
||||
|
||||
int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,int alen)
|
||||
{
|
||||
int len = RTA_LENGTH(alen);
|
||||
struct rtattr *rta;
|
||||
|
||||
if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
|
||||
printf("addattr_l ERROR: message exceeded bound of %d\n",maxlen);
|
||||
return -1;
|
||||
}
|
||||
rta = BR_NLMSG_TAIL(n);
|
||||
rta->rta_type = type;
|
||||
rta->rta_len = len;
|
||||
memcpy(RTA_DATA(rta), data, alen);
|
||||
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netlink_socket(unsigned long groups)
|
||||
{
|
||||
socklen_t addr_len;
|
||||
struct sockaddr_nl snl;
|
||||
int fd = -1;
|
||||
int ret;
|
||||
|
||||
|
||||
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (fd < 0) {
|
||||
rpc_log_error("Netlink: Cannot open netlink socket : (%s)",strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
if (ret < 0) {
|
||||
rpc_log_error("Netlink: Cannot set netlink socket flags : (%s)",strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&snl, 0, sizeof (snl));
|
||||
snl.nl_family = AF_NETLINK;
|
||||
snl.nl_groups = groups; /*设为0 表示不用多播,其他情况按照设置的组来进行多播,就是会多播到这些组*/
|
||||
|
||||
ret = bind(fd, (struct sockaddr *) &snl, sizeof (snl));
|
||||
if (ret < 0) {
|
||||
rpc_log_error("Netlink: Cannot bind netlink socket : (%s)",
|
||||
strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr_len = sizeof (snl);
|
||||
ret = getsockname(fd, (struct sockaddr *) &snl, &addr_len);
|
||||
if (ret < 0 || addr_len != sizeof (snl)) {
|
||||
printf("Netlink: Cannot getsockname : (%s)",strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (snl.nl_family != AF_NETLINK) {
|
||||
printf("Netlink: Wrong address family %d",snl.nl_family);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
br_seq = time(NULL);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int rtnl_talk(int fd , struct nlmsghdr *n,
|
||||
struct nlmsghdr *answer, size_t maxlen)
|
||||
{
|
||||
int status;
|
||||
struct nlmsghdr *h;
|
||||
struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
|
||||
struct iovec iov = {
|
||||
.iov_base = n,
|
||||
.iov_len = n->nlmsg_len
|
||||
};
|
||||
struct msghdr msg = {
|
||||
.msg_name = &nladdr,
|
||||
.msg_namelen = sizeof(nladdr),
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
char buf[32768] = {};
|
||||
|
||||
n->nlmsg_seq = ++br_seq;
|
||||
|
||||
if (answer == NULL)
|
||||
n->nlmsg_flags |= NLM_F_ACK;
|
||||
|
||||
status = sendmsg(fd, &msg, 0);
|
||||
if (status < 0) {
|
||||
perror("Cannot talk to rtnetlink");
|
||||
return -1;
|
||||
}
|
||||
|
||||
iov.iov_base = buf;
|
||||
while (1) {
|
||||
iov.iov_len = sizeof(buf);
|
||||
status = recvmsg(fd, &msg, 0);
|
||||
|
||||
if (status < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
printf("netlink receive error %s (%d)\n",strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
if (status == 0) {
|
||||
printf("EOF on netlink\n");
|
||||
return -1;
|
||||
}
|
||||
if (msg.msg_namelen != sizeof(nladdr)) {
|
||||
printf("sender address length == %d\n",msg.msg_namelen);
|
||||
exit(1);
|
||||
}
|
||||
for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
|
||||
int len = h->nlmsg_len;
|
||||
int l = len - sizeof(*h);
|
||||
|
||||
if (l < 0 || len > status) {
|
||||
if (msg.msg_flags & MSG_TRUNC) {
|
||||
printf("Truncated message\n");
|
||||
return -1;
|
||||
}
|
||||
printf("!!!malformed message: len=%d\n",len);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (nladdr.nl_pid != 0 ||
|
||||
h->nlmsg_seq != br_seq) {
|
||||
/* Don't forget to skip that message. */
|
||||
status -= NLMSG_ALIGN(len);
|
||||
h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (h->nlmsg_type == NLMSG_ERROR) {
|
||||
struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
|
||||
|
||||
if (l < sizeof(struct nlmsgerr)) {
|
||||
fprintf(stderr, "ERROR truncated\n");
|
||||
} else if (!err->error) {
|
||||
if (answer)
|
||||
memcpy(answer, h,
|
||||
BR_MIN(maxlen, h->nlmsg_len));
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = -err->error;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (answer) {
|
||||
memcpy(answer, h,
|
||||
BR_MIN(maxlen, h->nlmsg_len));
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Unexpected reply!!!\n");
|
||||
|
||||
status -= NLMSG_ALIGN(len);
|
||||
h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
|
||||
}
|
||||
|
||||
if (msg.msg_flags & MSG_TRUNC) {
|
||||
printf("Message truncated\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status) {
|
||||
fprintf(stderr, "!!!Remnant of size %d\n", status);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void parse_rtattr(struct rtattr **tb, int max, struct rtattr *rta, int len)
|
||||
{
|
||||
while (RTA_OK(rta, len)) {
|
||||
if (rta->rta_type <= max)
|
||||
tb[rta->rta_type] = rta;
|
||||
rta = RTA_NEXT(rta, len);
|
||||
}
|
||||
}
|
||||
|
||||
int get_br_from_port(char *port_name , char *br_name)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct ifinfomsg i;
|
||||
char buf[1024];
|
||||
}req;
|
||||
|
||||
if(if_nametoindex(port_name) == 0)
|
||||
{
|
||||
return RET_NOTFOUND;
|
||||
}
|
||||
|
||||
memset(&req,0,sizeof(req));
|
||||
|
||||
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||
req.n.nlmsg_flags = NLM_F_REQUEST ;
|
||||
req.n.nlmsg_type = RTM_GETLINK; /*消息类型*/
|
||||
req.i.ifi_family = PF_BRIDGE;
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
char buf[16384];
|
||||
}answer;
|
||||
|
||||
memset(&answer,0,sizeof(answer));
|
||||
|
||||
if(br_fd < 0){
|
||||
br_fd = netlink_socket(0);
|
||||
}
|
||||
|
||||
if(br_fd <0){
|
||||
printf("netlink_socket failed\n");
|
||||
return RET_SYSERR;
|
||||
}
|
||||
|
||||
addattr_l(&req.n, sizeof(req), IFLA_IFNAME, port_name, strlen(port_name)+1);
|
||||
if (rtnl_talk(br_fd, &req.n, &answer.n, sizeof(answer)) < 0)
|
||||
return RET_SYSERR;
|
||||
|
||||
struct ifinfomsg *ifi = NLMSG_DATA(&answer.n);
|
||||
struct rtattr *tb[IFLA_MAX+1];
|
||||
|
||||
printf("struct ifinfomsg: ifi_family=%u,ifi_index=%d\n",
|
||||
ifi->ifi_family,ifi->ifi_index);
|
||||
|
||||
|
||||
int len = answer.n.nlmsg_len - NLMSG_LENGTH(sizeof (struct ifinfomsg));
|
||||
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
|
||||
|
||||
printf("enum : IFLA_IFNAME=%s,IFLA_MTU=%d,IFLA_TXQLEN=%d\n",
|
||||
(char *)RTA_DATA(tb[IFLA_IFNAME]),
|
||||
*(int *)RTA_DATA(tb[IFLA_MTU]),
|
||||
*(int *)RTA_DATA(tb[IFLA_TXQLEN]));
|
||||
|
||||
printf("if_nametoindex:%d\n",if_nametoindex((char *)RTA_DATA(tb[IFLA_IFNAME])));
|
||||
|
||||
if (tb[IFLA_MASTER]) {
|
||||
int master = rta_getattr_u32(tb[IFLA_MASTER]);
|
||||
char if_name[INTERFACE_NAMSIZ] = {0};
|
||||
|
||||
if_indextoname(master, if_name);
|
||||
printf("master:%s\n", if_name);
|
||||
|
||||
if(br_get_bridge_info(if_name, NULL) == 0)
|
||||
{
|
||||
strncpy(br_name, if_name, BR_NAMSIZ - 1);
|
||||
br_name[BR_NAMSIZ - 1] = 0;
|
||||
return RET_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return RET_NOTFOUND;
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef BRNETLINK_H_
|
||||
#define BRNETLINK_H_
|
||||
|
||||
int get_br_from_port(char *port_name , char *br_name);
|
||||
|
||||
#endif
|
||||
|
|
@ -118,4 +118,5 @@ 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);
|
||||
extern int br_for_port_num(const char *brname, int *cnt);
|
||||
#endif
|
||||
|
|
|
@ -118,7 +118,6 @@ static int old_get_bridge_info(const char *bridge, struct bridge_info *info)
|
|||
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;
|
||||
|
||||
|
@ -128,6 +127,10 @@ static int old_get_bridge_info(const char *bridge, struct bridge_info *info)
|
|||
return errno;
|
||||
}
|
||||
|
||||
if(info)
|
||||
{
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
memcpy(&info->designated_root, &i.designated_root, 8);
|
||||
memcpy(&info->bridge_id, &i.bridge_id, 8);
|
||||
info->root_path_cost = i.root_path_cost;
|
||||
|
@ -147,6 +150,8 @@ static int old_get_bridge_info(const char *bridge, struct bridge_info *info)
|
|||
__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;
|
||||
}
|
||||
|
@ -167,6 +172,8 @@ int br_get_bridge_info(const char *bridge, struct bridge_info *info)
|
|||
goto fallback;
|
||||
}
|
||||
|
||||
if(info)
|
||||
{
|
||||
memset(info, 0, sizeof(*info));
|
||||
fetch_id(path, "root_id", &info->designated_root);
|
||||
fetch_id(path, "bridge_id", &info->bridge_id);
|
||||
|
@ -188,6 +195,8 @@ int br_get_bridge_info(const char *bridge, struct bridge_info *info)
|
|||
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;
|
||||
|
|
|
@ -145,6 +145,23 @@ int br_foreach_bridge(int (*iterator)(const char *, void *),
|
|||
return ret;
|
||||
}
|
||||
|
||||
int br_cnt_num(const char *name, void *arg)
|
||||
{
|
||||
int *cnt = arg;
|
||||
|
||||
(*cnt)++;
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
int br_for_bridge_num(int *cnt)
|
||||
{
|
||||
*cnt = 0;
|
||||
br_foreach_bridge(br_cnt_num, cnt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only used if sysfs is not available.
|
||||
*/
|
||||
|
@ -222,3 +239,75 @@ int br_foreach_port(const char *brname,
|
|||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only used if sysfs is not available.
|
||||
*/
|
||||
static int old_for_port_num(const char *brname, int *cnt)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
*cnt = count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int br_for_port_num(const char *brname, int *cnt)
|
||||
{
|
||||
int i, count;
|
||||
struct dirent **namelist;
|
||||
char path[SYSFS_PATH_MAX];
|
||||
|
||||
*cnt = 0;
|
||||
|
||||
snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brif", brname);
|
||||
count = scandir(path, &namelist, 0, alphasort);
|
||||
if (count < 0)
|
||||
return old_for_port_num(brname, cnt);
|
||||
|
||||
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;
|
||||
|
||||
(*cnt)++;
|
||||
}
|
||||
for (i = 0; i < count; i++)
|
||||
free(namelist[i]);
|
||||
free(namelist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -236,6 +236,92 @@ int conf_value_in_block_del(char *conf_path, char *start_str,
|
|||
return conf_file_write(conf_path, sum_buf);
|
||||
}
|
||||
|
||||
int conf_value_block_del(char *conf_path, char *start_str, char *end_str)
|
||||
{
|
||||
char config_linebuf[IF_BUFF_LEN];
|
||||
int configbuf_lenth = strlen(conf_buff) + 5;
|
||||
long congig_lenth = 0;
|
||||
|
||||
boolean next_flag = FALSE;
|
||||
char *start_line = NULL;
|
||||
FILE *f = fopen(conf_path, "r+");
|
||||
|
||||
if(f == NULL)
|
||||
{
|
||||
printf("OPEN CONFIG FALID\n");
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
|
||||
congig_lenth = ftell(f);
|
||||
|
||||
char sum_buf[congig_lenth + configbuf_lenth];
|
||||
|
||||
memset(sum_buf, 0, sizeof(sum_buf));
|
||||
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
memset(config_linebuf, 0, sizeof(config_linebuf));
|
||||
|
||||
while(fgets(config_linebuf, IF_BUFF_LEN,f) != NULL)
|
||||
{
|
||||
/* 该做的事情已经做完 */
|
||||
if(next_flag == TRUE)
|
||||
{
|
||||
strcat(sum_buf, config_linebuf);
|
||||
goto next_while;
|
||||
}
|
||||
|
||||
/* 判断是否是空行 */
|
||||
if(strlen(config_linebuf) < 3)
|
||||
{
|
||||
strcat(sum_buf, config_linebuf);
|
||||
goto next_while;
|
||||
}
|
||||
|
||||
/* 没有找到接口配置块,则继续循环 */
|
||||
if(start_line == NULL)
|
||||
{
|
||||
start_line = strstr(config_linebuf, start_str);
|
||||
if(start_line == NULL)
|
||||
{
|
||||
strcat(sum_buf, config_linebuf);
|
||||
}
|
||||
goto next_while;
|
||||
}
|
||||
|
||||
/* 已经到了end, 删除结束*/
|
||||
if(strstr(config_linebuf, end_str))
|
||||
{
|
||||
strcat(sum_buf, config_linebuf);
|
||||
next_flag = TRUE;
|
||||
goto next_while;
|
||||
}
|
||||
|
||||
if(next_flag == TRUE)
|
||||
{
|
||||
strcat(sum_buf, config_linebuf);
|
||||
}
|
||||
|
||||
next_while:
|
||||
|
||||
if(fgetc(f)==EOF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
fseek(f,-1,SEEK_CUR);
|
||||
|
||||
memset(config_linebuf, 0, sizeof(config_linebuf));
|
||||
}
|
||||
|
||||
remove(conf_path);
|
||||
fclose(f);
|
||||
|
||||
rpc_log_dbg("---sum_buf---->%s<----------\n",sum_buf);
|
||||
|
||||
return conf_file_write(conf_path, sum_buf);
|
||||
}
|
||||
|
||||
/*
|
||||
*添加修改文件(当配置文件中存在标记字段,则进行修改,若不存在则进行添加)
|
||||
|
|
Loading…
Reference in New Issue