Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / usr / ifmgmt.c
1 /*
2  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <string.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <ipxe/console.h>
27 #include <ipxe/netdevice.h>
28 #include <ipxe/device.h>
29 #include <ipxe/job.h>
30 #include <ipxe/monojob.h>
31 #include <ipxe/timer.h>
32 #include <usr/ifmgmt.h>
33
34 /** @file
35  *
36  * Network interface management
37  *
38  */
39
40 /** Default time to wait for link-up */
41 #define LINK_WAIT_TIMEOUT ( 15 * TICKS_PER_SEC )
42
43 /** Default unsuccessful configuration status code */
44 #define EADDRNOTAVAIL_CONFIG __einfo_error ( EINFO_EADDRNOTAVAIL_CONFIG )
45 #define EINFO_EADDRNOTAVAIL_CONFIG                                      \
46         __einfo_uniqify ( EINFO_EADDRNOTAVAIL, 0x01,                    \
47                           "No configuration methods succeeded" )
48
49 /**
50  * Open network device
51  *
52  * @v netdev            Network device
53  * @ret rc              Return status code
54  */
55 int ifopen ( struct net_device *netdev ) {
56         int rc;
57
58         if ( ( rc = netdev_open ( netdev ) ) != 0 ) {
59                 printf ( "Could not open %s: %s\n",
60                          netdev->name, strerror ( rc ) );
61                 return rc;
62         }
63
64         return 0;
65 }
66
67 /**
68  * Close network device
69  *
70  * @v netdev            Network device
71  */
72 void ifclose ( struct net_device *netdev ) {
73         netdev_close ( netdev );
74 }
75
76 /**
77  * Print network device error breakdown
78  *
79  * @v stats             Network device statistics
80  * @v prefix            Message prefix
81  */
82 static void ifstat_errors ( struct net_device_stats *stats,
83                             const char *prefix ) {
84         unsigned int i;
85
86         for ( i = 0 ; i < ( sizeof ( stats->errors ) /
87                             sizeof ( stats->errors[0] ) ) ; i++ ) {
88                 if ( stats->errors[i].count )
89                         printf ( "  [%s: %d x \"%s\"]\n", prefix,
90                                  stats->errors[i].count,
91                                  strerror ( stats->errors[i].rc ) );
92         }
93 }
94
95 /**
96  * Print status of network device
97  *
98  * @v netdev            Network device
99  */
100 void ifstat ( struct net_device *netdev ) {
101         printf ( "%s: %s using %s on %s (%s)\n"
102                  "  [Link:%s, TX:%d TXE:%d RX:%d RXE:%d]\n",
103                  netdev->name, netdev_addr ( netdev ),
104                  netdev->dev->driver_name, netdev->dev->name,
105                  ( netdev_is_open ( netdev ) ? "open" : "closed" ),
106                  ( netdev_link_ok ( netdev ) ? "up" : "down" ),
107                  netdev->tx_stats.good, netdev->tx_stats.bad,
108                  netdev->rx_stats.good, netdev->rx_stats.bad );
109         if ( ! netdev_link_ok ( netdev ) ) {
110                 printf ( "  [Link status: %s]\n",
111                          strerror ( netdev->link_rc ) );
112         }
113         ifstat_errors ( &netdev->tx_stats, "TXE" );
114         ifstat_errors ( &netdev->rx_stats, "RXE" );
115 }
116
117 /** Network device poller */
118 struct ifpoller {
119         /** Job control interface */
120         struct interface job;
121         /** Network device */
122         struct net_device *netdev;
123         /** Network device configurator (if applicable) */
124         struct net_device_configurator *configurator;
125         /**
126          * Check progress
127          *
128          * @v ifpoller          Network device poller
129          * @ret ongoing_rc      Ongoing job status code (if known)
130          */
131         int ( * progress ) ( struct ifpoller *ifpoller );
132 };
133
134 /**
135  * Report network device poller progress
136  *
137  * @v ifpoller          Network device poller
138  * @v progress          Progress report to fill in
139  * @ret ongoing_rc      Ongoing job status code (if known)
140  */
141 static int ifpoller_progress ( struct ifpoller *ifpoller,
142                                struct job_progress *progress __unused ) {
143
144         /* Hand off to current progress checker */
145         return ifpoller->progress ( ifpoller );
146 }
147
148 /** Network device poller operations */
149 static struct interface_operation ifpoller_job_op[] = {
150         INTF_OP ( job_progress, struct ifpoller *, ifpoller_progress ),
151 };
152
153 /** Network device poller descriptor */
154 static struct interface_descriptor ifpoller_job_desc =
155         INTF_DESC ( struct ifpoller, job, ifpoller_job_op );
156
157 /**
158  * Poll network device until completion
159  *
160  * @v netdev            Network device
161  * @v configurator      Network device configurator (if applicable)
162  * @v timeout           Timeout period, in ticks
163  * @v progress          Method to check progress
164  * @ret rc              Return status code
165  */
166 static int ifpoller_wait ( struct net_device *netdev,
167                            struct net_device_configurator *configurator,
168                            unsigned long timeout,
169                            int ( * progress ) ( struct ifpoller *ifpoller ) ) {
170         static struct ifpoller ifpoller = {
171                 .job = INTF_INIT ( ifpoller_job_desc ),
172         };
173
174         ifpoller.netdev = netdev;
175         ifpoller.configurator = configurator;
176         ifpoller.progress = progress;
177         intf_plug_plug ( &monojob, &ifpoller.job );
178         return monojob_wait ( "", timeout );
179 }
180
181 /**
182  * Check link-up progress
183  *
184  * @v ifpoller          Network device poller
185  * @ret ongoing_rc      Ongoing job status code (if known)
186  */
187 static int iflinkwait_progress ( struct ifpoller *ifpoller ) {
188         struct net_device *netdev = ifpoller->netdev;
189         int ongoing_rc = netdev->link_rc;
190
191         /* Terminate successfully if link is up */
192         if ( ongoing_rc == 0 )
193                 intf_close ( &ifpoller->job, 0 );
194
195         /* Otherwise, report link status as ongoing job status */
196         return ongoing_rc;
197 }
198
199 /**
200  * Wait for link-up, with status indication
201  *
202  * @v netdev            Network device
203  * @v timeout           Timeout period, in ticks
204  */
205 int iflinkwait ( struct net_device *netdev, unsigned long timeout ) {
206         int rc;
207
208         /* Ensure device is open */
209         if ( ( rc = ifopen ( netdev ) ) != 0 )
210                 return rc;
211
212         /* Return immediately if link is already up */
213         netdev_poll ( netdev );
214         if ( netdev_link_ok ( netdev ) )
215                 return 0;
216
217         /* Wait for link-up */
218         printf ( "Waiting for link-up on %s", netdev->name );
219         return ifpoller_wait ( netdev, NULL, timeout, iflinkwait_progress );
220 }
221
222 /**
223  * Check configuration progress
224  *
225  * @v ifpoller          Network device poller
226  * @ret ongoing_rc      Ongoing job status code (if known)
227  */
228 static int ifconf_progress ( struct ifpoller *ifpoller ) {
229         struct net_device *netdev = ifpoller->netdev;
230         struct net_device_configurator *configurator = ifpoller->configurator;
231         struct net_device_configuration *config;
232         int rc;
233
234         /* Do nothing unless configuration has completed */
235         if ( netdev_configuration_in_progress ( netdev ) )
236                 return 0;
237
238         /* Terminate with appropriate overall return status code */
239         if ( configurator ) {
240                 config = netdev_configuration ( netdev, configurator );
241                 rc = config->rc;
242         } else {
243                 rc = ( netdev_configuration_ok ( netdev ) ?
244                        0 : -EADDRNOTAVAIL_CONFIG );
245         }
246         intf_close ( &ifpoller->job, rc );
247
248         return rc;
249 }
250
251 /**
252  * Perform network device configuration
253  *
254  * @v netdev            Network device
255  * @v configurator      Network device configurator, or NULL to use all
256  * @ret rc              Return status code
257  */
258 int ifconf ( struct net_device *netdev,
259              struct net_device_configurator *configurator ) {
260         int rc;
261
262         /* Ensure device is open and link is up */
263         if ( ( rc = iflinkwait ( netdev, LINK_WAIT_TIMEOUT ) ) != 0 )
264                 return rc;
265
266         /* Start configuration */
267         if ( configurator ) {
268                 if ( ( rc = netdev_configure ( netdev, configurator ) ) != 0 ) {
269                         printf ( "Could not configure %s via %s: %s\n",
270                                  netdev->name, configurator->name,
271                                  strerror ( rc ) );
272                         return rc;
273                 }
274         } else {
275                 if ( ( rc = netdev_configure_all ( netdev ) ) != 0 ) {
276                         printf ( "Could not configure %s: %s\n",
277                                  netdev->name, strerror ( rc ) );
278                         return rc;
279                 }
280         }
281
282         /* Wait for configuration to complete */
283         printf ( "Configuring %s%s%s(%s %s)",
284                  ( configurator ? "[" : "" ),
285                  ( configurator ? configurator->name : "" ),
286                  ( configurator ? "] " : "" ),
287                  netdev->name, netdev->ll_protocol->ntoa ( netdev->ll_addr ) );
288         return ifpoller_wait ( netdev, configurator, 0, ifconf_progress );
289 }