diff options
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.c | 88 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.h | 1 | ||||
-rw-r--r-- | accel-pppd/ctrl/pppoe/pppoe.c | 85 | ||||
-rw-r--r-- | accel-pppd/ctrl/pppoe/pppoe.h | 4 | ||||
-rw-r--r-- | accel-pppd/include/vlan_mon.h | 9 | ||||
-rw-r--r-- | accel-pppd/libnetlink/iputils.c | 19 | ||||
-rw-r--r-- | accel-pppd/libnetlink/iputils.h | 4 | ||||
-rw-r--r-- | accel-pppd/libnetlink/libnetlink.c | 3 | ||||
-rw-r--r-- | accel-pppd/vlan-mon/vlan_mon.c | 66 | ||||
-rw-r--r-- | drivers/vlan_mon/vlan_mon.c | 36 | ||||
-rw-r--r-- | drivers/vlan_mon/vlan_mon.h | 1 |
11 files changed, 228 insertions, 88 deletions
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index e05ce9a9..bb1f9629 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -131,7 +131,7 @@ static const char *conf_attr_dhcp_opt82_circuit_id; static int conf_l4_redirect_table; static int conf_l4_redirect_on_reject; static const char *conf_l4_redirect_ipset; -static int conf_vlan_timeout = 30; +static int conf_vlan_timeout; static int conf_max_request = 3; static int conf_session_timeout; static int conf_idle_timeout; @@ -193,7 +193,7 @@ static void __ipoe_session_activate(struct ipoe_session *ses); static void ipoe_ses_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet *pack); static void __ipoe_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet *pack, int force); static void ipoe_session_keepalive(struct dhcpv4_packet *pack); -static void add_interface(const char *ifname, int ifindex, const char *opt, int parent_ifindex, int vid); +static void add_interface(const char *ifname, int ifindex, const char *opt, int parent_ifindex, int vid, int vlan_mon); static int get_offer_delay(); static void __ipoe_session_start(struct ipoe_session *ses); static int ipoe_rad_send_auth_request(struct rad_plugin_t *rad, struct rad_packet_t *pack); @@ -1109,7 +1109,7 @@ static void ipoe_session_finished(struct ap_session *s) pthread_mutex_lock(&ses->serv->lock); list_del(&ses->entry); - if ((ses->serv->vid || ses->serv->need_close) && list_empty(&ses->serv->sessions)) + if ((ses->serv->vlan_mon || ses->serv->need_close) && list_empty(&ses->serv->sessions)) triton_context_call(&ses->serv->ctx, (triton_event_func)ipoe_serv_release, ses->serv); pthread_mutex_unlock(&ses->serv->lock); @@ -1913,6 +1913,8 @@ void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph, struct _ar struct ipoe_session *ses; in_addr_t saddr = arph ? arph->ar_spa : iph->saddr; + log_debug("ipoe: recv up %08x\n", saddr); + pthread_mutex_lock(&serv_lock); list_for_each_entry(serv, &serv_list, entry) { if (serv->ifindex != ifindex) @@ -2100,7 +2102,7 @@ static void ipoe_serv_release(struct ipoe_serv *serv) } pthread_mutex_unlock(&serv->lock); - if (serv->vid && !serv->need_close && !ap_shutdown && !serv->opt_auto) { + if (serv->vlan_mon && !serv->need_close && !ap_shutdown && !serv->opt_auto) { if (serv->timer.tpd) triton_timer_mod(&serv->timer, 0); else @@ -2147,7 +2149,7 @@ static void ipoe_serv_release(struct ipoe_serv *serv) if (!serv->opt_auto) ipoe_nl_del_interface(serv->ifindex); - if (serv->vid) { + if (serv->vlan_mon) { log_info2("ipoe: remove vlan %s\n", serv->ifname); iplink_vlan_del(serv->ifindex); vlan_mon_add_vid(serv->parent_ifindex, ETH_P_IP, serv->vid); @@ -2286,10 +2288,8 @@ static void set_vlan_timeout(struct ipoe_serv *serv) serv->timer.expire = ipoe_serv_timeout; serv->timer.expire_tv.tv_sec = conf_vlan_timeout; - pthread_mutex_lock(&serv->lock); if (list_empty(&serv->sessions)) triton_timer_add(&serv->ctx, &serv->timer, 0); - pthread_mutex_unlock(&serv->lock); } void ipoe_vlan_mon_notify(int ifindex, int vid, int vlan_ifindex) @@ -2315,7 +2315,7 @@ void ipoe_vlan_mon_notify(int ifindex, int vid, int vlan_ifindex) return; } - svid = iplink_vlan_get_vid(ifindex); + svid = iplink_vlan_get_vid(ifindex, NULL); #ifdef USE_LUA if (!memcmp(conf_vlan_name, "lua:", 4)) @@ -2334,12 +2334,9 @@ void ipoe_vlan_mon_notify(int ifindex, int vid, int vlan_ifindex) pthread_mutex_lock(&serv_lock); list_for_each_entry(serv, &serv_list, entry) { if (serv->ifindex == vlan_ifindex) { - if (!serv->vid) { - serv->vid = vid; - serv->parent_ifindex = ifindex; - - if (conf_vlan_timeout) - triton_context_call(&serv->ctx, (triton_event_func)set_vlan_timeout, serv); + if (!serv->vlan_mon) { + serv->vlan_mon = 1; + set_vlan_timeout(serv); } pthread_mutex_unlock(&serv_lock); return; @@ -2416,15 +2413,16 @@ void ipoe_vlan_mon_notify(int ifindex, int vid, int vlan_ifindex) if (r < 0) continue; - add_interface(ifname, ifr.ifr_ifindex, opt->val, ifindex, vid); + add_interface(ifname, ifr.ifr_ifindex, opt->val, ifindex, vid, 1); return; } else if (ptr - opt->val == len && memcmp(opt->val, ifname, len) == 0) { - add_interface(ifname, ifr.ifr_ifindex, opt->val, ifindex, vid); + add_interface(ifname, ifr.ifr_ifindex, opt->val, ifindex, vid, 1); return; } } log_warn("ipoe: vlan %s not started\n", ifname); + iplink_vlan_del(ifr.ifr_ifindex); } static void ipoe_serv_timeout(struct triton_timer_t *t) @@ -2436,7 +2434,7 @@ static void ipoe_serv_timeout(struct triton_timer_t *t) ipoe_serv_release(serv); } -static void add_interface(const char *ifname, int ifindex, const char *opt, int parent_ifindex, int vid) +static void add_interface(const char *ifname, int ifindex, const char *opt, int parent_ifindex, int vid, int vlan_mon) { char *str0 = NULL, *str, *ptr1, *ptr2; int end; @@ -2633,6 +2631,9 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int } pthread_mutex_unlock(&serv_lock); + if (vid && !vlan_mon && vlan_mon_check_busy(parent_ifindex, vid)) + return; + if (!opt_auto) { if (opt_up) ipoe_nl_add_interface(ifindex, opt_mode); @@ -2695,7 +2696,7 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int #ifdef USE_LUA serv->opt_lua_username_func = opt_lua_username_func; #endif - serv->parent_ifindex = parent_ifindex = parent_ifindex; + serv->parent_ifindex = parent_ifindex; serv->vid = vid; serv->active = 1; INIT_LIST_HEAD(&serv->sessions); @@ -2718,10 +2719,9 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int if (serv->opt_arp) serv->arp = arpd_start(serv); - if (vid) { - serv->timer.expire = ipoe_serv_timeout; - serv->timer.expire_tv.tv_sec = conf_vlan_timeout; - triton_timer_add(&serv->ctx, &serv->timer, 0); + if (vlan_mon) { + serv->vlan_mon = 1; + set_vlan_timeout(serv); } if (serv->opt_auto && !serv->opt_shared) @@ -2749,6 +2749,7 @@ static void load_interface(const char *opt) const char *ptr; struct ifreq ifr; struct ipoe_serv *serv; + int vid, iflink = 0; for (ptr = opt; *ptr && *ptr != ','; ptr++); @@ -2763,7 +2764,7 @@ static void load_interface(const char *opt) continue; if (!strcmp(serv->ifname, ifr.ifr_name)) { - add_interface(serv->ifname, serv->ifindex, opt, 0, 0); + add_interface(serv->ifname, serv->ifindex, opt, 0, 0, 0); return; } } @@ -2773,15 +2774,17 @@ static void load_interface(const char *opt) return; } - add_interface(ifr.ifr_name, ifr.ifr_ifindex, opt, 0, 0); + vid = iplink_vlan_get_vid(ifr.ifr_ifindex, &iflink); + + add_interface(ifr.ifr_name, ifr.ifr_ifindex, opt, iflink, vid, 0); } -static int __load_interface_re(int index, int flags, const char *name, struct iplink_arg *arg) +static int __load_interface_re(int index, int flags, const char *name, int iflink, int vid, struct iplink_arg *arg) { if (pcre_exec(arg->re, NULL, name, strlen(name), 0, 0, NULL, 0) < 0) return 0; - add_interface(name, index, arg->opt, 0, 0); + add_interface(name, index, arg->opt, iflink, vid, 0); return 0; } @@ -2819,7 +2822,7 @@ static void load_interface_re(const char *opt) continue; if (pcre_exec(re, NULL, serv->ifname, strlen(serv->ifname), 0, 0, NULL, 0) >= 0) - add_interface(serv->ifname, serv->ifindex, opt, 0, 0); + add_interface(serv->ifname, serv->ifindex, opt, 0, 0, 0); } pcre_free(re); @@ -3049,14 +3052,21 @@ static void add_vlan_mon(const char *opt, long *mask) memcpy(mask1, mask, sizeof(mask1)); list_for_each_entry(serv, &serv_list, entry) { - if (serv->vid && serv->parent_ifindex == ifindex) + if (serv->parent_ifindex == ifindex && + !(mask1[serv->vid / (8*sizeof(long))] & 1lu << (serv->vid % (8*sizeof(long))))) { mask1[serv->vid / (8*sizeof(long))] |= 1lu << (serv->vid % (8*sizeof(long))); + + if (!serv->vlan_mon) { + serv->vlan_mon = 1; + set_vlan_timeout(serv); + } + } } vlan_mon_add(ifindex, ETH_P_IP, mask1, sizeof(mask1)); } -static int __load_vlan_mon_re(int index, int flags, const char *name, struct iplink_arg *arg) +static int __load_vlan_mon_re(int index, int flags, const char *name, int iflink, int vid, struct iplink_arg *arg) { struct ifreq ifr; long mask1[4096/8/sizeof(long)]; @@ -3065,21 +3075,25 @@ static int __load_vlan_mon_re(int index, int flags, const char *name, struct ipl if (pcre_exec(arg->re, NULL, name, strlen(name), 0, 0, NULL, 0) < 0) return 0; - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, name); - - ioctl(sock_fd, SIOCGIFFLAGS, &ifr); - - if (!(ifr.ifr_flags & IFF_UP)) { - ifr.ifr_flags |= IFF_UP; + if (!(flags & IFF_UP)) { + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, name); + ifr.ifr_flags = flags | IFF_UP; ioctl(sock_fd, SIOCSIFFLAGS, &ifr); } memcpy(mask1, arg->arg1, sizeof(mask1)); list_for_each_entry(serv, &serv_list, entry) { - if (serv->vid && serv->parent_ifindex == index) + if (serv->parent_ifindex == index && + !(mask1[serv->vid / (8*sizeof(long))] & (1lu << (serv->vid % (8*sizeof(long)))))) { mask1[serv->vid / (8*sizeof(long))] |= 1lu << (serv->vid % (8*sizeof(long))); + + if (!serv->vlan_mon) { + serv->vlan_mon = 1; + set_vlan_timeout(serv); + } + } } vlan_mon_add(index, ETH_P_IP, mask1, sizeof(mask1)); diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h index c8b03b9c..33bd6dfe 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.h +++ b/accel-pppd/ctrl/ipoe/ipoe.h @@ -64,6 +64,7 @@ struct ipoe_serv { int opt_ipv6:1; int need_close:1; int active:1; + int vlan_mon:1; }; struct ipoe_session { diff --git a/accel-pppd/ctrl/pppoe/pppoe.c b/accel-pppd/ctrl/pppoe/pppoe.c index be056908..70978cf3 100644 --- a/accel-pppd/ctrl/pppoe/pppoe.c +++ b/accel-pppd/ctrl/pppoe/pppoe.c @@ -133,8 +133,9 @@ static uint8_t bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static void pppoe_send_PADT(struct pppoe_conn_t *conn); void pppoe_server_free(struct pppoe_serv_t *serv); static int init_secret(struct pppoe_serv_t *serv); -static void __pppoe_server_start(const char *ifname, const char *opt, void *cli, int parent_ifindex, int vid); +static void __pppoe_server_start(const char *ifname, const char *opt, void *cli, int parent_ifindex, int vid, int vlan_mon); static void pppoe_serv_timeout(struct triton_timer_t *t); +static void set_vlan_timeout(struct pppoe_serv_t *serv); static void pppoe_serv_start_timer(struct pppoe_serv_t *serv) { @@ -147,10 +148,7 @@ static void pppoe_serv_start_timer(struct pppoe_serv_t *serv) if (conf_vlan_timeout) { serv->timer.expire = pppoe_serv_timeout; serv->timer.expire_tv.tv_sec = conf_vlan_timeout; - if (serv->timer.tpd) - triton_timer_mod(&serv->timer, 0); - else - triton_timer_add(&serv->ctx, &serv->timer, 0); + triton_timer_add(&serv->ctx, &serv->timer, 0); pthread_mutex_unlock(&serv->lock); } else { pthread_mutex_unlock(&serv->lock); @@ -179,7 +177,7 @@ static void disconnect(struct pppoe_conn_t *conn) if (conn->serv->stopping) { pthread_mutex_unlock(&conn->serv->lock); pppoe_server_free(conn->serv); - } else if (conn->serv->vid) { + } else if (conn->serv->vlan_mon) { triton_context_call(&conn->serv->ctx, (triton_event_func)pppoe_serv_start_timer, conn->serv); pthread_mutex_unlock(&conn->serv->lock); } else @@ -1291,12 +1289,12 @@ out_err: return -1; } -static int __pppoe_add_interface_re(int index, int flags, const char *name, struct iplink_arg *arg) +static int __pppoe_add_interface_re(int index, int flags, const char *name, int iflink, int vid, struct iplink_arg *arg) { if (pcre_exec(arg->re, NULL, name, strlen(name), 0, 0, NULL, 0) < 0) return 0; - __pppoe_server_start(name, arg->opt, arg->cli, 0, 0); + __pppoe_server_start(name, arg->opt, arg->cli, iflink, vid, 0); return 0; } @@ -1347,9 +1345,9 @@ void pppoe_server_start(const char *opt, void *cli) if (ptr) { memcpy(name, opt, ptr - opt); name[ptr - opt] = 0; - __pppoe_server_start(name, ptr, cli, 0, 0); + __pppoe_server_start(name, ptr, cli, -1, 0, 0); } else - __pppoe_server_start(opt, opt, cli, 0, 0); + __pppoe_server_start(opt, opt, cli, -1, 0, 0); } static void pppoe_serv_ctx_switch(struct triton_context_t *ctx, void *arg) @@ -1359,7 +1357,7 @@ static void pppoe_serv_ctx_switch(struct triton_context_t *ctx, void *arg) log_switch(ctx, NULL); } -static void __pppoe_server_start(const char *ifname, const char *opt, void *cli, int parent_ifindex, int vid) +static void __pppoe_server_start(const char *ifname, const char *opt, void *cli, int parent_ifindex, int vid, int vlan_mon) { struct pppoe_serv_t *serv; struct ifreq ifr; @@ -1384,6 +1382,9 @@ static void __pppoe_server_start(const char *ifname, const char *opt, void *cli, } pthread_rwlock_unlock(&serv_lock); + if (vid && !vlan_mon && vlan_mon_check_busy(parent_ifindex, vid)) + return; + serv = _malloc(sizeof(*serv)); memset(serv, 0, sizeof(*serv)); @@ -1447,10 +1448,15 @@ static void __pppoe_server_start(const char *ifname, const char *opt, void *cli, goto out_err; } + if (parent_ifindex == -1) + vid = iplink_vlan_get_vid(ifr.ifr_ifindex, &parent_ifindex); + serv->ctx.close = pppoe_serv_close; serv->ctx.before_switch = pppoe_serv_ctx_switch; serv->ifname = _strdup(ifname); serv->ifindex = ifr.ifr_ifindex; + serv->parent_ifindex = parent_ifindex; + serv->vid = vid; serv->net = net; pthread_mutex_init(&serv->lock, NULL); @@ -1468,14 +1474,9 @@ static void __pppoe_server_start(const char *ifname, const char *opt, void *cli, goto out_err; } - if (vid) { - serv->parent_ifindex = parent_ifindex; - serv->vid = vid; - if (conf_vlan_timeout) { - serv->timer.expire = pppoe_serv_timeout; - serv->timer.expire_tv.tv_sec = conf_vlan_timeout; - triton_timer_add(&serv->ctx, &serv->timer, 0); - } + if (vlan_mon) { + serv->vlan_mon = 1; + set_vlan_timeout(serv); } pthread_rwlock_wrlock(&serv_lock); @@ -1532,7 +1533,7 @@ void pppoe_server_free(struct pppoe_serv_t *serv) if (serv->timer.tpd) triton_timer_del(&serv->timer); - if (serv->vid) { + if (serv->vlan_mon) { log_info2("pppoe: remove vlan %s\n", serv->ifname); iplink_vlan_del(serv->ifindex); vlan_mon_add_vid(serv->parent_ifindex, ETH_P_PPP_DISC, serv->vid); @@ -1579,6 +1580,16 @@ static int init_secret(struct pppoe_serv_t *serv) return 0; } +static void set_vlan_timeout(struct pppoe_serv_t *serv) +{ + if (conf_vlan_timeout) { + serv->timer.expire = pppoe_serv_timeout; + serv->timer.expire_tv.tv_sec = conf_vlan_timeout; + if (!serv->conn_cnt) + triton_timer_add(&serv->ctx, &serv->timer, 0); + } +} + void pppoe_vlan_mon_notify(int ifindex, int vid, int vlan_ifindex) { struct conf_sect_t *sect = conf_get_section("pppoe"); @@ -1602,7 +1613,7 @@ void pppoe_vlan_mon_notify(int ifindex, int vid, int vlan_ifindex) return; } - svid = iplink_vlan_get_vid(ifindex); + svid = iplink_vlan_get_vid(ifindex, NULL); #ifdef USE_LUA if (!memcmp(conf_vlan_name, "lua:", 4)) @@ -1621,6 +1632,10 @@ void pppoe_vlan_mon_notify(int ifindex, int vid, int vlan_ifindex) pthread_rwlock_rdlock(&serv_lock); list_for_each_entry(serv, &serv_list, entry) { if (serv->ifindex == vlan_ifindex) { + if (!serv->vlan_mon) { + serv->vlan_mon = 1; + set_vlan_timeout(serv); + } pthread_rwlock_unlock(&serv_lock); return; } @@ -1696,15 +1711,16 @@ void pppoe_vlan_mon_notify(int ifindex, int vid, int vlan_ifindex) if (r < 0) continue; - __pppoe_server_start(ifr.ifr_name, opt->val, NULL, ifindex, vid); + __pppoe_server_start(ifr.ifr_name, opt->val, NULL, ifindex, vid, 1); return; } else if (ptr - opt->val == len && memcmp(opt->val, ifr.ifr_name, len) == 0) { - __pppoe_server_start(ifr.ifr_name, opt->val, NULL, ifindex, vid); + __pppoe_server_start(ifr.ifr_name, opt->val, NULL, ifindex, vid, 1); return; } } log_warn("pppoe: vlan %s not started\n", ifname); + iplink_vlan_del(ifr.ifr_ifindex); } static void add_vlan_mon(const char *opt, long *mask) @@ -1744,14 +1760,21 @@ static void add_vlan_mon(const char *opt, long *mask) memcpy(mask1, mask, sizeof(mask1)); list_for_each_entry(serv, &serv_list, entry) { - if (serv->vid && serv->parent_ifindex == ifindex) + if (serv->parent_ifindex == ifindex && + !(mask1[serv->vid / (8*sizeof(long))] & 1lu << (serv->vid % (8*sizeof(long))))) { mask1[serv->vid / (8*sizeof(long))] |= 1lu << (serv->vid % (8*sizeof(long))); + + if (!serv->vlan_mon) { + serv->vlan_mon = 1; + set_vlan_timeout(serv); + } + } } vlan_mon_add(ifindex, ETH_P_PPP_DISC, mask1, sizeof(mask1)); } -static int __load_vlan_mon_re(int index, int flags, const char *name, struct iplink_arg *arg) +static int __load_vlan_mon_re(int index, int flags, const char *name, int iflink, int vid, struct iplink_arg *arg) { struct ifreq ifr; long mask1[4096/8/sizeof(long)]; @@ -1773,8 +1796,15 @@ static int __load_vlan_mon_re(int index, int flags, const char *name, struct ipl memcpy(mask1, arg->arg1, sizeof(mask1)); list_for_each_entry(serv, &serv_list, entry) { - if (serv->vid && serv->parent_ifindex == index) + if (serv->parent_ifindex == index && + !(mask1[serv->vid / (8*sizeof(long))] & (1lu << (serv->vid % (8*sizeof(long)))))) { mask1[serv->vid / (8*sizeof(long))] |= 1lu << (serv->vid % (8*sizeof(long))); + + if (!serv->vlan_mon) { + serv->vlan_mon = 1; + set_vlan_timeout(serv); + } + } } vlan_mon_add(index, ETH_P_PPP_DISC, mask1, sizeof(mask1)); @@ -1996,13 +2026,12 @@ static void pppoe_init(void) return; } + load_interfaces(); load_config(); connlimit_loaded = triton_module_loaded("connlimit"); triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config); - - triton_context_call(NULL, (triton_event_func)load_interfaces, NULL); } DEFINE_INIT(21, pppoe_init); diff --git a/accel-pppd/ctrl/pppoe/pppoe.h b/accel-pppd/ctrl/pppoe/pppoe.h index a8830235..aac169ed 100644 --- a/accel-pppd/ctrl/pppoe/pppoe.h +++ b/accel-pppd/ctrl/pppoe/pppoe.h @@ -86,7 +86,6 @@ struct pppoe_serv_t DES_key_schedule des_ks; pthread_mutex_t lock; - int stopping:1; unsigned int conn_cnt; struct list_head conn_list; @@ -97,6 +96,9 @@ struct pppoe_serv_t int padi_cnt; int padi_limit; time_t last_padi_limit_warn; + + int stopping:1; + int vlan_mon:1; }; extern int conf_verbose; diff --git a/accel-pppd/include/vlan_mon.h b/accel-pppd/include/vlan_mon.h index 328e2303..ebcfdc6c 100644 --- a/accel-pppd/include/vlan_mon.h +++ b/accel-pppd/include/vlan_mon.h @@ -3,11 +3,12 @@ typedef void (*vlan_mon_notify)(int ifindex, int vid, int vlan_ifindex); -void vlan_mon_register_proto(int proto, vlan_mon_notify cb); +void vlan_mon_register_proto(uint16_t proto, vlan_mon_notify cb); -int vlan_mon_add(int ifindex, int proto, long *mask, int len); -int vlan_mon_add_vid(int ifindex, int proto, int vid); -int vlan_mon_del(int ifindex, int proto); +int vlan_mon_add(int ifindex, uint16_t proto, long *mask, int len); +int vlan_mon_add_vid(int ifindex, uint16_t proto, uint16_t vid); +int vlan_mon_del(int ifindex, uint16_t proto); +int vlan_mon_check_busy(int ifindex, uint16_t vid); int make_vlan_name(const char *pattern, const char *parent, int svid, int cvid, char *name); int parse_vlan_mon(const char *opt, long *mask); diff --git a/accel-pppd/libnetlink/iputils.c b/accel-pppd/libnetlink/iputils.c index e9b82857..ee536744 100644 --- a/accel-pppd/libnetlink/iputils.c +++ b/accel-pppd/libnetlink/iputils.c @@ -72,7 +72,9 @@ static int store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void * { struct ifinfomsg *ifi = NLMSG_DATA(n); struct rtattr *tb[IFLA_MAX + 1]; + struct rtattr *tb2[IFLA_MAX + 1]; struct arg *a = arg; + int vid = 0, iflink = 0; if (n->nlmsg_type != RTM_NEWLINK) return 0; @@ -86,9 +88,19 @@ static int store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void * if (tb[IFLA_IFNAME] == NULL) return 0; + if (tb[IFLA_LINKINFO]) { + parse_rtattr_nested(tb2, IFLA_MAX, tb[IFLA_LINKINFO]); + if (!strcmp(RTA_DATA(tb2[IFLA_INFO_KIND]), "vlan")) { + parse_rtattr_nested(tb2, IFLA_MAX, tb2[IFLA_INFO_DATA]); + vid = *(uint16_t *)RTA_DATA(tb2[IFLA_VLAN_ID]); + } + } + + if (tb[IFLA_LINK]) + iflink = *(int *)RTA_DATA(tb[IFLA_LINK]); //printf("%i %s\n", ifi->ifi_index, RTA_DATA(tb[IFLA_IFNAME])); - return a->func(ifi->ifi_index, ifi->ifi_flags, RTA_DATA(tb[IFLA_IFNAME]), a->arg); + return a->func(ifi->ifi_index, ifi->ifi_flags, RTA_DATA(tb[IFLA_IFNAME]), iflink, vid, a->arg); } int __export iplink_list(iplink_list_func func, void *arg) @@ -250,7 +262,7 @@ int __export iplink_vlan_del(int ifindex) return 0; } -int __export iplink_vlan_get_vid(int ifindex) +int __export iplink_vlan_get_vid(int ifindex, int *iflink) { struct iplink_req { struct nlmsghdr n; @@ -294,6 +306,9 @@ int __export iplink_vlan_get_vid(int ifindex) if (!tb[IFLA_LINKINFO]) return 0; + if (iflink && tb[IFLA_LINK]) + *iflink = *(int *)RTA_DATA(tb[IFLA_LINK]); + parse_rtattr_nested(tb, IFLA_MAX, tb[IFLA_LINKINFO]); if (strcmp(RTA_DATA(tb[IFLA_INFO_KIND]), "vlan")) diff --git a/accel-pppd/libnetlink/iputils.h b/accel-pppd/libnetlink/iputils.h index 1ce04103..d5f9701d 100644 --- a/accel-pppd/libnetlink/iputils.h +++ b/accel-pppd/libnetlink/iputils.h @@ -3,14 +3,14 @@ #include <linux/if_link.h> -typedef int (*iplink_list_func)(int index, int flags, const char *name, void *arg); +typedef int (*iplink_list_func)(int index, int flags, const char *name, int iflink, int vid, void *arg); int iplink_list(iplink_list_func func, void *arg); int iplink_get_stats(int ifindex, struct rtnl_link_stats *stats); int iplink_vlan_add(const char *ifname, int ifindex, int vid); int iplink_vlan_del(int ifindex); -int iplink_vlan_get_vid(int ifindex); +int iplink_vlan_get_vid(int ifindex, int *iflink); int ipaddr_add(int ifindex, in_addr_t addr, int mask); int ipaddr_del(int ifindex, in_addr_t addr, int mask); diff --git a/accel-pppd/libnetlink/libnetlink.c b/accel-pppd/libnetlink/libnetlink.c index 0536783a..aca16aff 100644 --- a/accel-pppd/libnetlink/libnetlink.c +++ b/accel-pppd/libnetlink/libnetlink.c @@ -382,7 +382,8 @@ int __export rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, memcpy(answer, h, h->nlmsg_len); return 0; } - log_debug("libnetlink: ""RTNETLINK answers: %s\n", strerror(errno)); + if (!ignore_einval) + log_debug("libnetlink: ""RTNETLINK answers: %s\n", strerror(errno)); } return -1; } diff --git a/accel-pppd/vlan-mon/vlan_mon.c b/accel-pppd/vlan-mon/vlan_mon.c index 5dcd0fd3..c243b7a9 100644 --- a/accel-pppd/vlan-mon/vlan_mon.c +++ b/accel-pppd/vlan-mon/vlan_mon.c @@ -34,7 +34,7 @@ static vlan_mon_notify cb[2]; static void init(void); -void __export vlan_mon_register_proto(int proto, vlan_mon_notify func) +void __export vlan_mon_register_proto(uint16_t proto, vlan_mon_notify func) { if (proto == ETH_P_PPP_DISC) proto = 1; @@ -47,7 +47,7 @@ void __export vlan_mon_register_proto(int proto, vlan_mon_notify func) init(); } -int __export vlan_mon_add(int ifindex, int proto, long *mask, int len) +int __export vlan_mon_add(int ifindex, uint16_t proto, long *mask, int len) { struct rtnl_handle rth; struct nlmsghdr *nlh; @@ -62,7 +62,7 @@ int __export vlan_mon_add(int ifindex, int proto, long *mask, int len) return -1; if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC)) { - log_error("ipoe: cannot open generic netlink socket\n"); + log_error("vlan_mon: cannot open generic netlink socket\n"); return -1; } @@ -76,7 +76,7 @@ int __export vlan_mon_add(int ifindex, int proto, long *mask, int len) addattr32(nlh, 1024, VLAN_MON_ATTR_IFINDEX, ifindex); addattr_l(nlh, 1024, VLAN_MON_ATTR_VLAN_MASK, mask, len); - addattr32(nlh, 1024, VLAN_MON_ATTR_PROTO, proto); + addattr_l(nlh, 1024, VLAN_MON_ATTR_PROTO, &proto, 2); if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) { log_error("vlan_mon: nl_add_vlan_mon: error talking to kernel\n"); @@ -88,7 +88,7 @@ int __export vlan_mon_add(int ifindex, int proto, long *mask, int len) return r; } -int __export vlan_mon_add_vid(int ifindex, int proto, int vid) +int __export vlan_mon_add_vid(int ifindex, uint16_t proto, uint16_t vid) { struct rtnl_handle rth; struct nlmsghdr *nlh; @@ -103,7 +103,7 @@ int __export vlan_mon_add_vid(int ifindex, int proto, int vid) return -1; if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC)) { - log_error("ipoe: cannot open generic netlink socket\n"); + log_error("vlan_mon: cannot open generic netlink socket\n"); return -1; } @@ -116,8 +116,8 @@ int __export vlan_mon_add_vid(int ifindex, int proto, int vid) ghdr->cmd = VLAN_MON_CMD_ADD_VID; addattr32(nlh, 1024, VLAN_MON_ATTR_IFINDEX, ifindex); - addattr32(nlh, 1024, VLAN_MON_ATTR_VID, vid); - addattr32(nlh, 1024, VLAN_MON_ATTR_PROTO, proto); + addattr_l(nlh, 1024, VLAN_MON_ATTR_VID, &vid, 2); + addattr_l(nlh, 1024, VLAN_MON_ATTR_PROTO, &proto, 2); if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) { log_error("vlan_mon: nl_add_vlan_mon_vid: error talking to kernel\n"); @@ -129,7 +129,7 @@ int __export vlan_mon_add_vid(int ifindex, int proto, int vid) return r; } -int __export vlan_mon_del(int ifindex, int proto) +int __export vlan_mon_del(int ifindex, uint16_t proto) { struct rtnl_handle rth; struct nlmsghdr *nlh; @@ -144,7 +144,7 @@ int __export vlan_mon_del(int ifindex, int proto) return -1; if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC)) { - log_error("ipoe: cannot open generic netlink socket\n"); + log_error("vlan_mon: cannot open generic netlink socket\n"); return -1; } @@ -157,7 +157,7 @@ int __export vlan_mon_del(int ifindex, int proto) ghdr->cmd = VLAN_MON_CMD_DEL; addattr32(nlh, 1024, VLAN_MON_ATTR_IFINDEX, ifindex); - addattr32(nlh, 1024, VLAN_MON_ATTR_PROTO, proto); + addattr_l(nlh, 1024, VLAN_MON_ATTR_PROTO, &proto, 2); if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) { log_error("vlan_mon: nl_del_vlan_mon: error talking to kernel\n"); @@ -197,6 +197,46 @@ void vlan_mon_clean() rtnl_close(&rth); } +int __export vlan_mon_check_busy(int ifindex, uint16_t vid) +{ + struct rtnl_handle rth; + struct nlmsghdr *nlh; + struct genlmsghdr *ghdr; + struct { + struct nlmsghdr n; + char buf[1024]; + } req; + int r = 0; + + if (vlan_mon_genl_id < 0) + return 0; + + if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC)) { + log_error("vlan_mon: cannot open generic netlink socket\n"); + return 0; + } + + nlh = &req.n; + nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nlh->nlmsg_type = vlan_mon_genl_id; + + ghdr = NLMSG_DATA(&req.n); + ghdr->cmd = VLAN_MON_CMD_CHECK_BUSY; + + addattr32(nlh, 1024, VLAN_MON_ATTR_IFINDEX, ifindex); + addattr_l(nlh, 1024, VLAN_MON_ATTR_VID, &vid, 2); + + if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 1) < 0 ) { + if (errno == EBUSY) + r = -1; + } + + rtnl_close(&rth); + + return r; +} + static void vlan_mon_handler(const struct sockaddr_nl *addr, struct nlmsghdr *h) { struct rtattr *tb[PKT_ATTR_MAX + 1]; @@ -227,8 +267,8 @@ static void vlan_mon_handler(const struct sockaddr_nl *addr, struct nlmsghdr *h) // continue; ifindex = *(uint32_t *)(RTA_DATA(tb2[VLAN_MON_ATTR_IFINDEX])); - vid = *(uint32_t *)(RTA_DATA(tb2[VLAN_MON_ATTR_VID])); - proto = *(uint32_t *)(RTA_DATA(tb2[VLAN_MON_ATTR_PROTO])); + vid = *(uint16_t *)(RTA_DATA(tb2[VLAN_MON_ATTR_VID])); + proto = *(uint16_t *)(RTA_DATA(tb2[VLAN_MON_ATTR_PROTO])); if (tb2[VLAN_MON_ATTR_VLAN_IFINDEX]) vlan_ifindex = *(uint32_t *)(RTA_DATA(tb2[VLAN_MON_ATTR_VLAN_IFINDEX])); diff --git a/drivers/vlan_mon/vlan_mon.c b/drivers/vlan_mon/vlan_mon.c index 16bb11e6..9a2d211d 100644 --- a/drivers/vlan_mon/vlan_mon.c +++ b/drivers/vlan_mon/vlan_mon.c @@ -490,6 +490,36 @@ static int vlan_mon_nl_cmd_del_vlan_mon(struct sk_buff *skb, struct genl_info *i return 0; } +static int vlan_mon_nl_cmd_check_busy(struct sk_buff *skb, struct genl_info *info) +{ + int ifindex, vid; + struct net_device *dev; + int ret = 0; + + if (!info->attrs[VLAN_MON_ATTR_IFINDEX] || !info->attrs[VLAN_MON_ATTR_VID]) + return -EINVAL; + + ifindex = nla_get_u32(info->attrs[VLAN_MON_ATTR_IFINDEX]); + vid = nla_get_u16(info->attrs[VLAN_MON_ATTR_VID]); + + down(&vlan_mon_lock); + + rtnl_lock(); + dev = __dev_get_by_index(&init_net, ifindex); + if (dev) { + struct vlan_dev *d = dev->ml_priv; + if (d) { + if (d->busy[vid / (8*sizeof(long))] & (1lu << (vid % (8*sizeof(long))))) + ret = -EBUSY; + } + } + rtnl_unlock(); + + up(&vlan_mon_lock); + + return ret; +} + static struct nla_policy vlan_mon_nl_policy[VLAN_MON_ATTR_MAX + 1] = { [VLAN_MON_ATTR_NONE] = { .type = NLA_UNSPEC, }, [VLAN_MON_ATTR_VLAN_MASK] = { .type = NLA_BINARY, .len = 4096/8 }, @@ -523,6 +553,12 @@ static struct genl_ops vlan_mon_nl_ops[] = { .policy = vlan_mon_nl_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = VLAN_MON_CMD_CHECK_BUSY, + .doit = vlan_mon_nl_cmd_check_busy, + .policy = vlan_mon_nl_policy, + .flags = GENL_ADMIN_PERM, + }, }; static struct genl_family vlan_mon_nl_family = { diff --git a/drivers/vlan_mon/vlan_mon.h b/drivers/vlan_mon/vlan_mon.h index ff5c8523..d5f9f360 100644 --- a/drivers/vlan_mon/vlan_mon.h +++ b/drivers/vlan_mon/vlan_mon.h @@ -9,6 +9,7 @@ enum { VLAN_MON_CMD_ADD_VID, VLAN_MON_CMD_DEL, VLAN_MON_NOTIFY, + VLAN_MON_CMD_CHECK_BUSY, __VLAN_MON_CMD_MAX, }; |