.../linux/generic/files/drivers/net/phy/swconfig.c | 111 ++++++++++++++++++++-
 target/linux/generic/files/include/linux/switch.h  |   2 +
 2 files changed, 112 insertions(+), 1 deletion(-)

diff --git a/target/linux/generic/files/drivers/net/phy/swconfig.c b/target/linux/generic/files/drivers/net/phy/swconfig.c
index e772c94..9904a11 100644
--- a/target/linux/generic/files/drivers/net/phy/swconfig.c
+++ b/target/linux/generic/files/drivers/net/phy/swconfig.c
@@ -23,6 +23,12 @@
 #include <linux/capability.h>
 #include <linux/skbuff.h>
 #include <linux/switch.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <net/netlink.h>
+#include <linux/rtnetlink.h>

 //#define DEBUG 1
 #ifdef DEBUG
@@ -38,6 +44,23 @@
 MODULE_AUTHOR("Felix Fietkau <n...@openwrt.org>");
 MODULE_LICENSE("GPL");

+static struct hrtimer poll_timer;
+static ktime_t poll_timer_interval;
+static unsigned long base_interval;
+static bool first_poll = 1;
+
+static unsigned long interval = 40;
+module_param(interval, ulong, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(interval,"Polling interval in ms for port state scanning.");
+
+static bool poll_enable = 0;
+module_param(poll_enable, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(poll_enable,"Grant port state polling.");
+
+static int port_if_id[] = {8,4,5,6,7};
+module_param_array(port_if_id, int, NULL, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(port_if_id,"Preconfigured one port per vlan interface indexes.");
+
 static int swdev_id = 0;
 static struct list_head swdevs;
 static DEFINE_SPINLOCK(swdevs_lock);
@@ -955,7 +978,11 @@ register_switch(struct switch_dev *dev, struct net_device *netdev)
        }
        BUG_ON(!dev->alias);

+       dev->port_state = NULL;
+
        if (dev->ports > 0) {
+               dev->port_state = kzalloc(sizeof(int) * dev->ports, GFP_KERNEL);
+               dev->port_state[dev->ports-1] = 1; /* CPU port */
                dev->portbuf = kzalloc(sizeof(struct switch_port) * dev->ports,
                                GFP_KERNEL);
                if (!dev->portbuf)
@@ -1000,6 +1027,7 @@ unregister_switch(struct switch_dev *dev)
 {
        swconfig_destroy_led_trigger(dev);
        kfree(dev->portbuf);
+       kfree(dev->port_state);
        mutex_lock(&dev->sw_mutex);
        swconfig_lock();
        list_del(&dev->dev_list);
@@ -1008,12 +1036,93 @@ unregister_switch(struct switch_dev *dev)
 }
 EXPORT_SYMBOL_GPL(unregister_switch);

+static int get_link_state(struct switch_dev *dev, int port)
+{
+       struct switch_port_link link;
+       link.link=0;
+
+       if(dev->ops->get_port_link(dev, port, &link))
+               return -EINVAL;
+
+       if(link.link)
+               return 1;
+
+       return 0;
+}
+
+static void modify_if_carrier(int port, int ifidx, int state)
+{
+       struct net_device *dev;
+       list_for_each_entry(dev, &init_net.dev_base_head, dev_list) {
+               if(dev->ifindex == ifidx) {
+                       if(state == 1)
+                               netif_carrier_on(dev);
+                       else
+                               netif_carrier_off(dev);
+               }
+       }
+}
+
+static enum hrtimer_restart poll_timer_callback(struct hrtimer *timer)
+{
+       struct switch_dev *dev;
+       int i,cur_port_state;
+
+       if(poll_enable) {
+                       dev = list_entry((&swdevs)->next, typeof(*dev), 
dev_list);
+                       for(i=0; i < dev->ports-1; i++) {
+                               cur_port_state = get_link_state(dev,i);
+                               if(dev->port_state[i] == 0 && cur_port_state == 
1) {
+                                       modify_if_carrier(i,port_if_id[i],1);
+                                       dev->port_state[i] = 1;
+                               }
+                               else if(dev->port_state[i] == 1 && 
cur_port_state == 0) {
+                                       modify_if_carrier(i,port_if_id[i],0);
+                                       dev->port_state[i] = 0;
+                               }
+                               else if(first_poll) {
+                                       if(cur_port_state){
+                                               
modify_if_carrier(i,port_if_id[i],1);
+                                       }
+                                       else{
+                                               
modify_if_carrier(i,port_if_id[i],0);
+                                       }
+                               }
+                       }
+                       first_poll = 0;
+       }
+       else {
+               if(base_interval == interval)
+                       base_interval = interval+1;
+               first_poll = 1;
+               poll_timer_interval = ktime_set(0, 100*1000000);
+               hrtimer_forward(&poll_timer, ktime_get(), poll_timer_interval);
+               return HRTIMER_RESTART;
+       }
+
+       if(interval != base_interval) {
+               if(interval < 1)
+                       interval = 1;
+               poll_timer_interval = ktime_set(0, interval*1000000);
+               base_interval = interval;
+       }
+
+       hrtimer_forward(&poll_timer, ktime_get(), poll_timer_interval);
+       return HRTIMER_RESTART;
+}

 static int __init
 swconfig_init(void)
 {
        int i, err;

+       base_interval = interval;
+       poll_timer_interval = ktime_set(0, interval*1000000);
+       hrtimer_init(&poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       poll_timer.function = &poll_timer_callback;
+
+       hrtimer_start(&poll_timer, poll_timer_interval, HRTIMER_MODE_REL);
+
        INIT_LIST_HEAD(&swdevs);
        err = genl_register_family(&switch_fam);
        if (err)
@@ -1036,8 +1145,8 @@ static void __exit
 swconfig_exit(void)
 {
        genl_unregister_family(&switch_fam);
+       hrtimer_cancel(&poll_timer);
 }

 module_init(swconfig_init);
 module_exit(swconfig_exit);
-
diff --git a/target/linux/generic/files/include/linux/switch.h b/target/linux/generic/files/include/linux/switch.h
index 4f4085e..26ac605 100644
--- a/target/linux/generic/files/include/linux/switch.h
+++ b/target/linux/generic/files/include/linux/switch.h
@@ -194,6 +194,8 @@ struct switch_dev {
        struct mutex sw_mutex;
        struct switch_port *portbuf;

+       int *port_state;
+
        char buf[128];

 #ifdef CONFIG_SWCONFIG_LEDS


On 03/01/14 11:49, Florian Fainelli wrote:
Le 2 janv. 2014 13:27, "Lévai Tamás" <levai.ta...@t-online.hu
<mailto:levai.ta...@t-online.hu>> a écrit :
 >
 >
 > Running  OpenFlow  on  OpenWrt  is  a  well  known  use-case. Of‐
 > softswitch is a user space implementation of OF software  switch.
 > If  you want to use fast failover mechanisms with it, you have to
 > provide port  status  information  to  ofsoftwitch.  Polling  via
 > swconfig   and  swconfig   API   could  be used in this case, but
 > they are bloated, because they use context switch for  each  port
 > status  request.  Lowering  this  overhead  is important, because
 > ofsoftswitch utilizes the whole CPU.
 >
 > To minimize the context switches I implemented  the  port  status
 > polling  in kernel mode using the swconfig kernel module. With my
 > patch the swconfig kernel module is able to  modify  the  carrier
 > state on predefined interfaces from &init_net according to a port
 > status change in the switch.
 >
 > As a consequence,  netlink  messages  notify user space  programs
 > about  status  changes of ports / interfaces. This was useful for
 > us to test fast failover mechanisms of an  OpenFlow  switch.   We
 > believe  this  patch is generally useful beyond our routing soft‐
 > ware use‐case.
 >
 > More information can be found on this web page:
 > http://centaur.sch.bme.hu/~leait/projects/openwrt/
 >
 > If you are looking only for the patch:
 >
http://centaur.sch.bme.hu/~leait/projects/openwrt/patches/swconfig_poll.patch

Can you post the patch as an email such that we can provide inline
responses?

Thanks!

 >
 > Tamas Levai
 >
 > Tested by:
 >  * Tamas  Levai <levai.ta...@t-online.hu
<mailto:levai.ta...@t-online.hu>>
 >  * Felician Nemeth <neme...@tmit.bme.hu <mailto:neme...@tmit.bme.hu>>
 > _______________________________________________
 > openwrt-devel mailing list
 > openwrt-devel@lists.openwrt.org <mailto:openwrt-devel@lists.openwrt.org>
 > https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel



_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to