diff options
-rw-r--r-- | accel-pppd/ctrl/ipoe/dhcpv4.c | 17 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.c | 64 | ||||
-rw-r--r-- | drivers/ipoe/ipoe.c | 31 |
3 files changed, 79 insertions, 33 deletions
diff --git a/accel-pppd/ctrl/ipoe/dhcpv4.c b/accel-pppd/ctrl/ipoe/dhcpv4.c index f5408b08..fa763445 100644 --- a/accel-pppd/ctrl/ipoe/dhcpv4.c +++ b/accel-pppd/ctrl/ipoe/dhcpv4.c @@ -41,6 +41,7 @@ static mempool_t pack_pool; static mempool_t opt_pool; static LIST_HEAD(relay_list); +static pthread_mutex_t relay_lock = PTHREAD_MUTEX_INITIALIZER; static int dhcpv4_read(struct triton_md_handler_t *h); int dhcpv4_packet_add_opt(struct dhcpv4_packet *pack, int type, const void *data, int len); @@ -838,6 +839,7 @@ struct dhcpv4_relay *dhcpv4_relay_create(const char *_addr, const char *_giaddr, laddr.sin_addr.s_addr = giaddr; laddr.sin_port = htons(DHCP_SERV_PORT); + pthread_mutex_lock(&relay_lock); list_for_each_entry(r, &relay_list, entry) { if (r->addr == addr && r->giaddr == giaddr) goto found; @@ -852,7 +854,7 @@ struct dhcpv4_relay *dhcpv4_relay_create(const char *_addr, const char *_giaddr, sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (!sock) { log_error("socket: %s\n", strerror(errno)); - goto out_err; + goto out_err_unlock; } if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &f, sizeof(f))) @@ -860,12 +862,12 @@ struct dhcpv4_relay *dhcpv4_relay_create(const char *_addr, const char *_giaddr, if (bind(sock, &laddr, sizeof(laddr))) { log_error("dhcpv4: relay: %s: bind: %s\n", _addr, strerror(errno)); - goto out_err; + goto out_err_unlock; } if (connect(sock, &raddr, sizeof(raddr))) { log_error("dhcpv4: relay: %s: connect: %s\n", _addr, strerror(errno)); - goto out_err; + goto out_err_unlock; } fcntl(sock, F_SETFL, O_NONBLOCK); @@ -875,7 +877,7 @@ struct dhcpv4_relay *dhcpv4_relay_create(const char *_addr, const char *_giaddr, r->hnd.read = dhcpv4_relay_read; triton_context_register(&r->ctx, NULL); - triton_md_register_handler(ctx, &r->hnd); + triton_md_register_handler(&r->ctx, &r->hnd); triton_md_enable_handler(&r->hnd, MD_MODE_READ); triton_context_wakeup(&r->ctx); @@ -886,9 +888,14 @@ found: c->ctx = ctx; c->recv = recv; list_add_tail(&c->entry, &r->ctx_list); + + pthread_mutex_unlock(&relay_lock); return r; +out_err_unlock: + pthread_mutex_unlock(&relay_lock); + out_err: if (sock != -1) close(sock); @@ -900,6 +907,7 @@ void dhcpv4_relay_free(struct dhcpv4_relay *r, struct triton_context_t *ctx) { struct dhcpv4_relay_ctx *c; + pthread_mutex_lock(&relay_lock); list_for_each_entry(c, &r->ctx_list, entry) { if (c->ctx == ctx) { list_del(&c->entry); @@ -916,6 +924,7 @@ void dhcpv4_relay_free(struct dhcpv4_relay *r, struct triton_context_t *ctx) triton_context_unregister(&r->ctx); _free(r); } + pthread_mutex_unlock(&relay_lock); } int dhcpv4_relay_send(struct dhcpv4_relay *relay, struct dhcpv4_packet *request, uint32_t server_id, const char *agent_circuit_id, const char *agent_remote_id) diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index f792e1bc..5e88f5d9 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -56,7 +56,6 @@ struct iplink_arg { pcre *re; const char *opt; long *arg1; - int arg2; }; struct unit_cache { @@ -685,7 +684,7 @@ static void ipoe_ifcfg_add(struct ipoe_session *ses) ses->ifcfg = 1; } -static void ipoe_ifcfg_del(struct ipoe_session *ses) +static void ipoe_ifcfg_del(struct ipoe_session *ses, int lock) { struct ipoe_serv *serv = ses->serv; @@ -696,10 +695,14 @@ static void ipoe_ifcfg_del(struct ipoe_session *ses) if (ses->serv->opt_shared) { ipoe_serv_del_addr(ses->serv, ses->siaddr); } else { - pthread_mutex_lock(&serv->lock); - if (ipaddr_del(serv->ifindex, ses->siaddr)) - log_ppp_warn("ipoe: failed to remove addess from interface '%s'\n", serv->ifname); - pthread_mutex_unlock(&serv->lock); + if (lock) + pthread_mutex_lock(&serv->lock); + if (ipaddr_del(serv->ifindex, ses->siaddr)) { + if (lock) + log_ppp_warn("ipoe: failed to remove addess from interface '%s'\n", serv->ifname); + } + if (lock) + pthread_mutex_unlock(&serv->lock); } } } @@ -848,7 +851,6 @@ static void ipoe_session_started(struct ap_session *s) static void ipoe_session_free(struct ipoe_session *ses) { - if (ses->started) __sync_sub_and_fetch(&stat_active, 1); else @@ -906,7 +908,7 @@ static void ipoe_session_finished(struct ap_session *s) dhcpv4_relay_send_release(ses->serv->dhcpv4_relay, ses->hwaddr, ses->xid, ses->yiaddr, ses->client_id, ses->relay_agent, ses->serv->ifname, conf_agent_remote_id); if (ses->ifcfg) - ipoe_ifcfg_del(ses); + ipoe_ifcfg_del(ses, 1); if (ses->dhcpv4) dhcpv4_free(ses->dhcpv4); @@ -1655,7 +1657,7 @@ static void ipoe_serv_release(struct ipoe_serv *serv) } pthread_mutex_unlock(&serv->lock); - if (serv->vid && !serv->need_close) { + if (serv->vid && !serv->need_close && !ap_shutdown) { if (serv->timer.tpd) triton_timer_mod(&serv->timer, 0); else @@ -1780,7 +1782,7 @@ static void ipoe_drop_sessions(struct ipoe_serv *serv, struct ipoe_session *skip ses->terminating = 1; if (ses->ifcfg) { - ipoe_ifcfg_del(ses); + ipoe_ifcfg_del(ses, 0); ses->ifcfg = 0; } @@ -1853,8 +1855,10 @@ void ipoe_vlan_notify(int ifindex, int vid) log_info2("ipoe: create vlan %s\n", ifr.ifr_name); - if (iplink_vlan_add(ifr.ifr_name, ifindex, vid)) + if (iplink_vlan_add(ifr.ifr_name, ifindex, vid)) { log_warn("ipoe: vlan-mon: %s: failed to add vlan\n", ifr.ifr_name); + return; + } if (ioctl(sock_fd, SIOCGIFINDEX, &ifr, sizeof(ifr))) { log_error("ipoe: vlan-mon: %s: failed to get interface index\n", ifr.ifr_name); @@ -1993,6 +1997,7 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int if (opt_up) ipoe_nl_add_interface(ifindex); + pthread_mutex_lock(&serv_lock); list_for_each_entry(serv, &serv_list, entry) { if (strcmp(ifname, serv->ifname)) continue; @@ -2044,8 +2049,10 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int if (str0) _free(str0); + pthread_mutex_unlock(&serv_lock); return; } + pthread_mutex_unlock(&serv_lock); opt = strchr(opt, ','); if (opt) @@ -2117,7 +2124,9 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int triton_context_wakeup(&serv->ctx); + pthread_mutex_lock(&serv_lock); list_add_tail(&serv->entry, &serv_list); + pthread_mutex_unlock(&serv_lock); if (str0) _free(str0); @@ -2436,9 +2445,9 @@ static int parse_vlan_mon(const char *opt, long *mask) ptr = strchr(opt, 0); if (*ptr == ',') - memset(mask, 0xff, 4096/8/sizeof(long)); + memset(mask, 0xff, 4096/8); else if (*ptr == 0) { - memset(mask, 0, 4096/8/sizeof(long)); + memset(mask, 0, 4096/8); return 0; } else goto out_err; @@ -2458,10 +2467,10 @@ static int parse_vlan_mon(const char *opt, long *mask) } for (; vid < vid2; vid++) - mask[vid / (8*sizeof(long))] &= ~(1 << (vid % (8*sizeof(long)))); + mask[vid / (8*sizeof(long))] &= ~(1lu << (vid % (8*sizeof(long)))); } - mask[vid / (8*sizeof(long))] &= ~(1 << (vid % (8*sizeof(long)))); + mask[vid / (8*sizeof(long))] &= ~(1lu << (vid % (8*sizeof(long)))); if (*ptr2 == 0) break; @@ -2479,11 +2488,13 @@ out_err: return -1; } -static void add_vlan_mon(const char *opt, long *mask, int len) +static void add_vlan_mon(const char *opt, long *mask) { const char *ptr; struct ifreq ifr; int ifindex; + long mask1[4096/8/sizeof(long)]; + struct ipoe_serv *serv; for (ptr = opt; *ptr && *ptr != ','; ptr++); @@ -2512,12 +2523,20 @@ static void add_vlan_mon(const char *opt, long *mask, int len) ioctl(sock_fd, SIOCSIFFLAGS, &ifr); } - ipoe_nl_add_vlan_mon(ifindex, mask, len); + memcpy(mask1, mask, sizeof(mask1)); + list_for_each_entry(serv, &serv_list, entry) { + if (serv->vid && serv->parent_ifindex == ifindex) + mask1[serv->vid / (8*sizeof(long))] |= 1lu << (serv->vid % (8*sizeof(long))); + } + + ipoe_nl_add_vlan_mon(ifindex, mask1, sizeof(mask1)); } static int __load_vlan_mon_re(int index, int flags, const char *name, struct iplink_arg *arg) { struct ifreq ifr; + long mask1[4096/8/sizeof(long)]; + struct ipoe_serv *serv; if (pcre_exec(arg->re, NULL, name, strlen(name), 0, 0, NULL, 0) < 0) return 0; @@ -2532,8 +2551,14 @@ static int __load_vlan_mon_re(int index, int flags, const char *name, struct ipl 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) + mask1[serv->vid / (8*sizeof(long))] |= 1lu << (serv->vid % (8*sizeof(long))); + } - ipoe_nl_add_vlan_mon(index, arg->arg1, arg->arg2); + ipoe_nl_add_vlan_mon(index, mask1, sizeof(mask1)); return 0; } @@ -2563,7 +2588,6 @@ static void load_vlan_mon_re(const char *opt, long *mask, int len) arg.re = re; arg.opt = opt; arg.arg1 = mask; - arg.arg2 = len; iplink_list((iplink_list_func)__load_vlan_mon_re, &arg); @@ -2592,7 +2616,7 @@ static void load_vlan_mon(struct conf_sect_t *sect) if (strlen(opt->val) > 3 && !memcmp(opt->val, "re:", 3)) load_vlan_mon_re(opt->val, mask, sizeof(mask)); else - add_vlan_mon(opt->val, mask, sizeof(mask)); + add_vlan_mon(opt->val, mask); } } diff --git a/drivers/ipoe/ipoe.c b/drivers/ipoe/ipoe.c index fc944a8e..447b48b9 100644 --- a/drivers/ipoe/ipoe.c +++ b/drivers/ipoe/ipoe.c @@ -106,6 +106,7 @@ struct vlan_dev { struct list_head entry; int ifindex; + spinlock_t lock; unsigned long vid[4096/8/sizeof(long)]; }; @@ -865,16 +866,19 @@ static int vlan_pt_recv(struct sk_buff *skb, struct net_device *dev, struct pack if (d->ifindex == dev->ifindex) goto found; } - rcu_read_lock(); + rcu_read_unlock(); goto out; found: //pr_info("found %i\n", d->ifindex); - if (d->vid[vid / (8*sizeof(long))] & (1 << (vid % (8*sizeof(long))))) + if (d->vid[vid / (8*sizeof(long))] & (1lu << (vid % (8*sizeof(long))))) vid = -1; - else - d->vid[vid / (8*sizeof(long))] |= 1 << (vid % (8*sizeof(long))); - rcu_read_lock(); + else { + spin_lock(&d->lock); + d->vid[vid / (8*sizeof(long))] |= 1lu << (vid % (8*sizeof(long))); + spin_unlock(&d->lock); + } + rcu_read_unlock(); if (vid == -1) goto out; @@ -908,6 +912,8 @@ static void vlan_do_notify(struct work_struct *w) int id = 1; unsigned long flags; + //pr_info("vlan_do_notify\n"); + while (1) { spin_lock_irqsave(&vlan_lock, flags); if (list_empty(&vlan_notifies)) @@ -926,10 +932,12 @@ static void vlan_do_notify(struct work_struct *w) header = genlmsg_put(report_skb, 0, ipoe_nl_mcg.id, &ipoe_nl_family, 0, IPOE_VLAN_NOTIFY); } + //pr_info("notify %i vlan %i\n", id, n->vid); + ns = nla_nest_start(report_skb, id++); if (!ns) goto nl_err; - + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32) if (nla_put_u32(report_skb, IPOE_ATTR_IFINDEX, n->ifindex)) #else @@ -1628,20 +1636,22 @@ static int ipoe_nl_cmd_add_vlan_mon(struct sk_buff *skb, struct genl_info *info) } d->ifindex = ifindex; + spin_lock_init(&d->lock); if (info->attrs[IPOE_ATTR_VLAN_MASK]) { memcpy(d->vid, nla_data(info->attrs[IPOE_ATTR_VLAN_MASK]), min((int)nla_len(info->attrs[IPOE_ATTR_VLAN_MASK]), (int)sizeof(d->vid))); + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) if (dev->features & NETIF_F_HW_VLAN_FILTER) { for (i = 1; i < 4096; i++) { - if (!(d->vid[i / (8*sizeof(long))] & (1 << (i % (8*sizeof(long)))))) + if (!(d->vid[i / (8*sizeof(long))] & (1lu << (i % (8*sizeof(long)))))) dev->netdev_ops->ndo_vlan_rx_add_vid(dev, i); } } #else if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) { for (i = 1; i < 4096; i++) { - if (!(d->vid[i / (8*sizeof(long))] & (1 << (i % (8*sizeof(long)))))) + if (!(d->vid[i / (8*sizeof(long))] & (1lu << (i % (8*sizeof(long)))))) dev->netdev_ops->ndo_vlan_rx_add_vid(dev, htons(ETH_P_8021Q), i); } } @@ -1662,6 +1672,7 @@ static int ipoe_nl_cmd_add_vlan_mon_vid(struct sk_buff *skb, struct genl_info *i struct vlan_dev *d; int ifindex, vid; struct net_device *dev; + unsigned long flags; if (!info->attrs[IPOE_ATTR_IFINDEX] || !info->attrs[IPOE_ATTR_ADDR]) return -EINVAL; @@ -1683,7 +1694,9 @@ static int ipoe_nl_cmd_add_vlan_mon_vid(struct sk_buff *skb, struct genl_info *i down(&ipoe_wlock); list_for_each_entry(d, &vlan_devices, entry) { if (d->ifindex == ifindex) { - d->vid[vid / (8*sizeof(long))] &= ~(1 << (vid % (8*sizeof(long)))); + spin_lock_irqsave(&d->lock, flags); + d->vid[vid / (8*sizeof(long))] &= ~(1lu << (vid % (8*sizeof(long)))); + spin_unlock_irqrestore(&d->lock, flags); #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) if (dev->features & NETIF_F_HW_VLAN_FILTER) dev->netdev_ops->ndo_vlan_rx_add_vid(dev, vid); |