diff mbox

new parameter boot=on|off for "-net nic" and "-device" NIC devices

Message ID 1284479215-24679-1-git-send-email-bernhard.kohl@nsn.com
State New
Headers show

Commit Message

Bernhard Kohl Sept. 14, 2010, 3:46 p.m. UTC
This patch was motivated by the following use case: In our system
the VMs usually have 4 NICs, any combination of virtio-net-pci and
pci-assign NIC devices. The VMs boot via gPXE preferably over the
pci-assign devices.

There is no way to make this working with a combination of the
current options -net -pcidevice -device -optionrom -boot.

With the parameter boot=off it is possible to avoid loading
and using gPXE option ROMs either for old style "-net nic" or
for "-device" NIC devices. So we can select which NIC is used
for booting.

A side effect of the boot=off parameter is that unneeded ROMs
which might waste memory are not longer loaded. E.g. if you have
2 virtio-net-pci and 2 pci-assign NICs in sum 4 option ROMs are
loaded and the virtio ROMs take precedence over the pci-assign
ROMs. The BIOS uses the first gPXE ROM which it finds and only
needs one of them even if there are more NICs of the same type.

Without using the boot=on|off parameter the current behaviour
does not change.

Signed-off-by: Thomas Ostler <thomas.ostler@nsn.com>
Signed-off-by: Bernhard Kohl <bernhard.kohl@nsn.com>
---
 hw/pci.c        |    8 +++++++-
 hw/pci.h        |    1 +
 hw/qdev.c       |    6 ++++++
 hw/qdev.h       |    1 +
 net.c           |    8 ++++++++
 net.h           |    1 +
 qemu-options.hx |    8 ++++++--
 vl.c            |   27 +++++++++++++++++++++++++++
 8 files changed, 57 insertions(+), 3 deletions(-)

Comments

Michael S. Tsirkin Sept. 19, 2010, 4:07 p.m. UTC | #1
On Tue, Sep 14, 2010 at 05:46:55PM +0200, Bernhard Kohl wrote:
> This patch was motivated by the following use case: In our system
> the VMs usually have 4 NICs, any combination of virtio-net-pci and
> pci-assign NIC devices. The VMs boot via gPXE preferably over the
> pci-assign devices.
> 
> There is no way to make this working with a combination of the
> current options -net -pcidevice -device -optionrom -boot.
> 
> With the parameter boot=off it is possible to avoid loading
> and using gPXE option ROMs either for old style "-net nic" or
> for "-device" NIC devices. So we can select which NIC is used
> for booting.
> 
> A side effect of the boot=off parameter is that unneeded ROMs
> which might waste memory are not longer loaded. E.g. if you have
> 2 virtio-net-pci and 2 pci-assign NICs in sum 4 option ROMs are
> loaded and the virtio ROMs take precedence over the pci-assign
> ROMs. The BIOS uses the first gPXE ROM which it finds and only
> needs one of them even if there are more NICs of the same type.
> 
> Without using the boot=on|off parameter the current behaviour
> does not change.
> 
> Signed-off-by: Thomas Ostler <thomas.ostler@nsn.com>
> Signed-off-by: Bernhard Kohl <bernhard.kohl@nsn.com>

I think this is useful, however:

- We have bit properties which handle parsing on/off
  and other formats automatically. Please don't use string.
- boot is not a great property name for PCI: what
  you actually do is disable option rom.
  So maybe call it 'rom' or something like that?
- given you have added a property, it can now
  be changed with -device. and visible in -device ?
  This also has an advantage of only applying to pci devices
  (-net option would appear to apply to non-pci but have no effect).
  Please do not add more flag parsing in qdemu-options, net and vl.c

To summarize, just add a qdev bit option and check
the bit.

> ---
>  hw/pci.c        |    8 +++++++-
>  hw/pci.h        |    1 +
>  hw/qdev.c       |    6 ++++++
>  hw/qdev.h       |    1 +
>  net.c           |    8 ++++++++
>  net.h           |    1 +
>  qemu-options.hx |    8 ++++++--
>  vl.c            |   27 +++++++++++++++++++++++++++
>  8 files changed, 57 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/pci.c b/hw/pci.c
> index a98d6f3..055a2be 100644
> --- a/hw/pci.c
> +++ b/hw/pci.c
> @@ -71,6 +71,7 @@ static struct BusInfo pci_bus_info = {
>          DEFINE_PROP_UINT32("rombar",  PCIDevice, rom_bar, 1),
>          DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
>                          QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
> +        DEFINE_PROP_STRING("boot", PCIDevice, boot),
>          DEFINE_PROP_END_OF_LIST()
>      }
>  };
> @@ -1513,6 +1514,10 @@ PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
>  
>      pci_dev = pci_create(bus, devfn, pci_nic_names[i]);
>      dev = &pci_dev->qdev;
> +    if (nd->name)
> +        dev->id = qemu_strdup(nd->name);
> +    if (nd->no_boot)
> +        dev->no_boot = 1;
>      qdev_set_nic_properties(dev, nd);
>      if (qdev_init(dev) < 0)
>          return NULL;
> @@ -1693,7 +1698,8 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
>      /* rom loading */
>      if (pci_dev->romfile == NULL && info->romfile != NULL)
>          pci_dev->romfile = qemu_strdup(info->romfile);
> -    pci_add_option_rom(pci_dev);
> +    if (!qdev->no_boot)
> +        pci_add_option_rom(pci_dev);
>  
>      if (qdev->hotplugged) {
>          rc = bus->hotplug(bus->hotplug_qdev, pci_dev, 1);
> diff --git a/hw/pci.h b/hw/pci.h
> index 1eab7e7..20aa038 100644
> --- a/hw/pci.h
> +++ b/hw/pci.h
> @@ -172,6 +172,7 @@ struct PCIDevice {
>      char *romfile;
>      ram_addr_t rom_offset;
>      uint32_t rom_bar;
> +    char *boot;
>  };
>  
>  PCIDevice *pci_register_device(PCIBus *bus, const char *name,
> diff --git a/hw/qdev.c b/hw/qdev.c
> index 35858cb..8445bc9 100644
> --- a/hw/qdev.c
> +++ b/hw/qdev.c
> @@ -249,6 +249,10 @@ DeviceState *qdev_device_add(QemuOpts *opts)
>          qdev_free(qdev);
>          return NULL;
>      }
> +    if (qemu_opt_get(opts, "boot")) {
> +        if (!strcmp("off", qemu_strdup(qemu_opt_get(opts, "boot"))))
> +            qdev->no_boot = 1;
> +    }
>      if (qdev_init(qdev) < 0) {
>          qerror_report(QERR_DEVICE_INIT_FAILED, driver);
>          return NULL;
> @@ -421,6 +425,8 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
>          qdev_prop_exists(dev, "vectors")) {
>          qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
>      }
> +    if (nd->no_boot)
> +        qdev_prop_parse(dev, "boot", "off");
>  }
>  
>  static int next_block_unit[IF_COUNT];
> diff --git a/hw/qdev.h b/hw/qdev.h
> index 579328a..e7df371 100644
> --- a/hw/qdev.h
> +++ b/hw/qdev.h
> @@ -45,6 +45,7 @@ struct DeviceState {
>      QLIST_ENTRY(DeviceState) sibling;
>      int instance_id_alias;
>      int alias_required_for_version;
> +    int no_boot;
>  };
>  
>  typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent);
> diff --git a/net.c b/net.c
> index 3d0fde7..2370aca 100644
> --- a/net.c
> +++ b/net.c
> @@ -792,6 +792,10 @@ static int net_init_nic(QemuOpts *opts,
>      if (qemu_opt_get(opts, "addr")) {
>          nd->devaddr = qemu_strdup(qemu_opt_get(opts, "addr"));
>      }
> +    if (qemu_opt_get(opts, "boot")) {
> +        if (!strcmp("off", qemu_strdup(qemu_opt_get(opts, "boot"))))
> +            nd->no_boot = 1;
> +    }
>  
>      nd->macaddr[0] = 0x52;
>      nd->macaddr[1] = 0x54;
> @@ -877,6 +881,10 @@ static const struct {
>                  .type = QEMU_OPT_STRING,
>                  .help = "PCI device address",
>              }, {
> +                .name = "boot",
> +                .type = QEMU_OPT_STRING,
> +                .help = "gPXE boot (on (default), off)",
> +            }, {
>                  .name = "vectors",
>                  .type = QEMU_OPT_NUMBER,
>                  .help = "number of MSI-x vectors, 0 to disable MSI-X",
> diff --git a/net.h b/net.h
> index 518cf9c..288059b 100644
> --- a/net.h
> +++ b/net.h
> @@ -132,6 +132,7 @@ struct NICInfo {
>      VLANClientState *netdev;
>      int used;
>      int nvectors;
> +    int no_boot;
>  };
>  
>  extern int nb_nics;
> diff --git a/qemu-options.hx b/qemu-options.hx
> index a0b5ae9..6084aa9 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -959,8 +959,10 @@ DEF("smb", HAS_ARG, QEMU_OPTION_smb, "", QEMU_ARCH_ALL)
>  #endif
>  
>  DEF("net", HAS_ARG, QEMU_OPTION_net,
> -    "-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n"
> +    "-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v][,boot=on|off]\n"
>      "                create a new Network Interface Card and connect it to VLAN 'n'\n"
> +    "                use 'boot=on|off' to enable/disable loading of an option rom;\n"
> +    "                loading enabled is the default\n"
>  #ifdef CONFIG_SLIRP
>      "-net user[,vlan=n][,name=str][,net=addr[/mask]][,host=addr][,restrict=y|n]\n"
>      "         [,hostname=host][,dhcpstart=addr][,dns=addr][,tftp=dir][,bootfile=f]\n"
> @@ -1014,13 +1016,15 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
>  #endif
>      "socket],id=str[,option][,option][,...]\n", QEMU_ARCH_ALL)
>  STEXI
> -@item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}]
> +@item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}][,boot=on|off]
>  @findex -net
>  Create a new Network Interface Card and connect it to VLAN @var{n} (@var{n}
>  = 0 is the default). The NIC is an e1000 by default on the PC
>  target. Optionally, the MAC address can be changed to @var{mac}, the
>  device address set to @var{addr} (PCI cards only),
>  and a @var{name} can be assigned for use in monitor commands.
> +Optionally, with @option{boot=on|off}, you can enable/disable the loading of an option
> +rom; by default, loading is enabled.
>  Optionally, for PCI cards, you can specify the number @var{v} of MSI-X vectors
>  that the card should have; this option currently only affects virtio cards; set
>  @var{v} = 0 to disable MSI-X. If no @option{-net} option is specified, a single
> diff --git a/vl.c b/vl.c
> index 3f45aa9..2aad6b1 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -2459,6 +2459,33 @@ int main(int argc, char **argv, char **envp)
>                  if (!qemu_opts_parse(qemu_find_opts("device"), optarg, 1)) {
>                      exit(1);
>                  }
> +
> +                /* check whether option "boot" is present in the cmd string */
> +                /* for this a modified string is created that does not */
> +                /* contain the driver */
> +                /* if "boot" is present and set to "on", the relevant */
> +                /* variables are set in a way that net boot is possible and */
> +                /* that a present "romfile" is loaded for the given device */
> +                /* note that "default_net" is set to zero in order to avoid */
> +                /* creation of a default device if option "-net" is not */
> +                /* present in the complete command line */
> +                {
> +                   char  mod_optarg[128];
> +                   char  *mod_optarg_p;
> +
> +                   if ((mod_optarg_p = strchr(optarg, ',')))
> +                       strcpy(mod_optarg, ++mod_optarg_p);
> +                   else
> +                       strcpy(mod_optarg, optarg);
> +
> +                   if (get_param_value(mod_optarg, 128, "boot", mod_optarg) != 0) {
> +                       if (!strcmp("on", mod_optarg)) {
> +                           char buf[8]="n";
> +                           pstrcpy(boot_devices, sizeof(boot_devices), buf);
> +                           default_net = 0;
> +                       }
> +                   }
> +                }
>                  break;
>              case QEMU_OPTION_smp:
>                  smp_parse(optarg);
> -- 
> 1.7.2.2
>
Bernhard Kohl Sept. 21, 2010, 2:18 p.m. UTC | #2
Am 19.09.2010 18:07, schrieb ext Michael S. Tsirkin:
> On Tue, Sep 14, 2010 at 05:46:55PM +0200, Bernhard Kohl wrote:
>    
>> >  This patch was motivated by the following use case: In our system
>> >  the VMs usually have 4 NICs, any combination of virtio-net-pci and
>> >  pci-assign NIC devices. The VMs boot via gPXE preferably over the
>> >  pci-assign devices.
>> >  
>> >  There is no way to make this working with a combination of the
>> >  current options -net -pcidevice -device -optionrom -boot.
>> >  
>> >  With the parameter boot=off it is possible to avoid loading
>> >  and using gPXE option ROMs either for old style "-net nic" or
>> >  for "-device" NIC devices. So we can select which NIC is used
>> >  for booting.
>> >  
>> >  A side effect of the boot=off parameter is that unneeded ROMs
>> >  which might waste memory are not longer loaded. E.g. if you have
>> >  2 virtio-net-pci and 2 pci-assign NICs in sum 4 option ROMs are
>> >  loaded and the virtio ROMs take precedence over the pci-assign
>> >  ROMs. The BIOS uses the first gPXE ROM which it finds and only
>> >  needs one of them even if there are more NICs of the same type.
>> >  
>> >  Without using the boot=on|off parameter the current behaviour
>> >  does not change.
>> >  
>> >  Signed-off-by: Thomas Ostler<thomas.ostler@nsn.com>
>> >  Signed-off-by: Bernhard Kohl<bernhard.kohl@nsn.com>
>>      
> I think this is useful, however:
>
> - We have bit properties which handle parsing on/off
>    and other formats automatically. Please don't use string.
> - boot is not a great property name for PCI: what
>    you actually do is disable option rom.
>    So maybe call it 'rom' or something like that?
>    
Our main goal is to select a certain NIC's option rom for booting.
So the other roms are not needed and not loaded. We used 'boot'
as the property name as it is similar as in the '-drive' option to
select a certain disk for booting. What's about to call it 'bootrom'?
> - given you have added a property, it can now
>    be changed with -device. and visible in -device ?
>    This also has an advantage of only applying to pci devices
>    (-net option would appear to apply to non-pci but have no effect).
>    Please do not add more flag parsing in qdemu-options, net and vl.c
>    
I think it is OK that we don't support this new feature for the old
style '-net' option and only implement it for qdev / -device?
> To summarize, just add a qdev bit option and check
> the bit.
>
>    
In general, we will rework the patch and use all new qdev features.
There are also some memory leaks as Chris told us, because of the
usage of strdup.

This rework might take 2 weeks because of vacation.

Thanks
Bernhard
Michael S. Tsirkin Sept. 21, 2010, 2:52 p.m. UTC | #3
On Tue, Sep 21, 2010 at 04:18:56PM +0200, Bernhard Kohl wrote:
> Am 19.09.2010 18:07, schrieb ext Michael S. Tsirkin:
> >On Tue, Sep 14, 2010 at 05:46:55PM +0200, Bernhard Kohl wrote:
> >>>  This patch was motivated by the following use case: In our system
> >>>  the VMs usually have 4 NICs, any combination of virtio-net-pci and
> >>>  pci-assign NIC devices. The VMs boot via gPXE preferably over the
> >>>  pci-assign devices.
> >>>  >  There is no way to make this working with a combination of
> >>the
> >>>  current options -net -pcidevice -device -optionrom -boot.
> >>>  >  With the parameter boot=off it is possible to avoid
> >>loading
> >>>  and using gPXE option ROMs either for old style "-net nic" or
> >>>  for "-device" NIC devices. So we can select which NIC is used
> >>>  for booting.
> >>>  >  A side effect of the boot=off parameter is that unneeded
> >>ROMs
> >>>  which might waste memory are not longer loaded. E.g. if you have
> >>>  2 virtio-net-pci and 2 pci-assign NICs in sum 4 option ROMs are
> >>>  loaded and the virtio ROMs take precedence over the pci-assign
> >>>  ROMs. The BIOS uses the first gPXE ROM which it finds and only
> >>>  needs one of them even if there are more NICs of the same type.
> >>>  >  Without using the boot=on|off parameter the current
> >>behaviour
> >>>  does not change.
> >>>  >  Signed-off-by: Thomas Ostler<thomas.ostler@nsn.com>
> >>>  Signed-off-by: Bernhard Kohl<bernhard.kohl@nsn.com>
> >I think this is useful, however:
> >
> >- We have bit properties which handle parsing on/off
> >   and other formats automatically. Please don't use string.
> >- boot is not a great property name for PCI: what
> >   you actually do is disable option rom.
> >   So maybe call it 'rom' or something like that?
> Our main goal is to select a certain NIC's option rom for booting.
> So the other roms are not needed and not loaded. We used 'boot'
> as the property name as it is similar as in the '-drive' option to
> select a certain disk for booting. What's about to call it 'bootrom'?

Sounds good.

> >- given you have added a property, it can now
> >   be changed with -device. and visible in -device ?
> >   This also has an advantage of only applying to pci devices
> >   (-net option would appear to apply to non-pci but have no effect).
> >   Please do not add more flag parsing in qdemu-options, net and vl.c
> I think it is OK that we don't support this new feature for the old
> style '-net' option and only implement it for qdev / -device?


I think so, too.

> >To summarize, just add a qdev bit option and check
> >the bit.
> >
> In general, we will rework the patch and use all new qdev features.
> There are also some memory leaks as Chris told us, because of the
> usage of strdup.
> 
> This rework might take 2 weeks because of vacation.
> 
> Thanks
> Bernhard

Sounds good.
Anthony Liguori Sept. 21, 2010, 3:16 p.m. UTC | #4
On 09/19/2010 11:07 AM, Michael S. Tsirkin wrote:
> On Tue, Sep 14, 2010 at 05:46:55PM +0200, Bernhard Kohl wrote:
>    
>> This patch was motivated by the following use case: In our system
>> the VMs usually have 4 NICs, any combination of virtio-net-pci and
>> pci-assign NIC devices. The VMs boot via gPXE preferably over the
>> pci-assign devices.
>>
>> There is no way to make this working with a combination of the
>> current options -net -pcidevice -device -optionrom -boot.
>>
>> With the parameter boot=off it is possible to avoid loading
>> and using gPXE option ROMs either for old style "-net nic" or
>> for "-device" NIC devices. So we can select which NIC is used
>> for booting.
>>
>> A side effect of the boot=off parameter is that unneeded ROMs
>> which might waste memory are not longer loaded. E.g. if you have
>> 2 virtio-net-pci and 2 pci-assign NICs in sum 4 option ROMs are
>> loaded and the virtio ROMs take precedence over the pci-assign
>> ROMs. The BIOS uses the first gPXE ROM which it finds and only
>> needs one of them even if there are more NICs of the same type.
>>
>> Without using the boot=on|off parameter the current behaviour
>> does not change.
>>
>> Signed-off-by: Thomas Ostler<thomas.ostler@nsn.com>
>> Signed-off-by: Bernhard Kohl<bernhard.kohl@nsn.com>
>>      
> I think this is useful, however:
>
> - We have bit properties which handle parsing on/off
>    and other formats automatically. Please don't use string.
>    

This is unneeded.  Just do romfile= with -device and it will suppress 
the option rom loading.

IOW:

-device virtio-net-pci,romfile= -pcidevice ...

But BTW, you should be able to select the pci device by doing:

-boot cdn,menu=on

And then hitting F12.  We need to come up with a better way to let 
particular BEV or BCV devices to be chosen from the command line.

Regards,

Anthony Liguori

> - boot is not a great property name for PCI: what
>    you actually do is disable option rom.
>    So maybe call it 'rom' or something like that?
> - given you have added a property, it can now
>    be changed with -device. and visible in -device ?
>    This also has an advantage of only applying to pci devices
>    (-net option would appear to apply to non-pci but have no effect).
>    Please do not add more flag parsing in qdemu-options, net and vl.c
>
> To summarize, just add a qdev bit option and check
> the bit.
>
>    
>> ---
>>   hw/pci.c        |    8 +++++++-
>>   hw/pci.h        |    1 +
>>   hw/qdev.c       |    6 ++++++
>>   hw/qdev.h       |    1 +
>>   net.c           |    8 ++++++++
>>   net.h           |    1 +
>>   qemu-options.hx |    8 ++++++--
>>   vl.c            |   27 +++++++++++++++++++++++++++
>>   8 files changed, 57 insertions(+), 3 deletions(-)
>>
>> diff --git a/hw/pci.c b/hw/pci.c
>> index a98d6f3..055a2be 100644
>> --- a/hw/pci.c
>> +++ b/hw/pci.c
>> @@ -71,6 +71,7 @@ static struct BusInfo pci_bus_info = {
>>           DEFINE_PROP_UINT32("rombar",  PCIDevice, rom_bar, 1),
>>           DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
>>                           QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
>> +        DEFINE_PROP_STRING("boot", PCIDevice, boot),
>>           DEFINE_PROP_END_OF_LIST()
>>       }
>>   };
>> @@ -1513,6 +1514,10 @@ PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
>>
>>       pci_dev = pci_create(bus, devfn, pci_nic_names[i]);
>>       dev =&pci_dev->qdev;
>> +    if (nd->name)
>> +        dev->id = qemu_strdup(nd->name);
>> +    if (nd->no_boot)
>> +        dev->no_boot = 1;
>>       qdev_set_nic_properties(dev, nd);
>>       if (qdev_init(dev)<  0)
>>           return NULL;
>> @@ -1693,7 +1698,8 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
>>       /* rom loading */
>>       if (pci_dev->romfile == NULL&&  info->romfile != NULL)
>>           pci_dev->romfile = qemu_strdup(info->romfile);
>> -    pci_add_option_rom(pci_dev);
>> +    if (!qdev->no_boot)
>> +        pci_add_option_rom(pci_dev);
>>
>>       if (qdev->hotplugged) {
>>           rc = bus->hotplug(bus->hotplug_qdev, pci_dev, 1);
>> diff --git a/hw/pci.h b/hw/pci.h
>> index 1eab7e7..20aa038 100644
>> --- a/hw/pci.h
>> +++ b/hw/pci.h
>> @@ -172,6 +172,7 @@ struct PCIDevice {
>>       char *romfile;
>>       ram_addr_t rom_offset;
>>       uint32_t rom_bar;
>> +    char *boot;
>>   };
>>
>>   PCIDevice *pci_register_device(PCIBus *bus, const char *name,
>> diff --git a/hw/qdev.c b/hw/qdev.c
>> index 35858cb..8445bc9 100644
>> --- a/hw/qdev.c
>> +++ b/hw/qdev.c
>> @@ -249,6 +249,10 @@ DeviceState *qdev_device_add(QemuOpts *opts)
>>           qdev_free(qdev);
>>           return NULL;
>>       }
>> +    if (qemu_opt_get(opts, "boot")) {
>> +        if (!strcmp("off", qemu_strdup(qemu_opt_get(opts, "boot"))))
>> +            qdev->no_boot = 1;
>> +    }
>>       if (qdev_init(qdev)<  0) {
>>           qerror_report(QERR_DEVICE_INIT_FAILED, driver);
>>           return NULL;
>> @@ -421,6 +425,8 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
>>           qdev_prop_exists(dev, "vectors")) {
>>           qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
>>       }
>> +    if (nd->no_boot)
>> +        qdev_prop_parse(dev, "boot", "off");
>>   }
>>
>>   static int next_block_unit[IF_COUNT];
>> diff --git a/hw/qdev.h b/hw/qdev.h
>> index 579328a..e7df371 100644
>> --- a/hw/qdev.h
>> +++ b/hw/qdev.h
>> @@ -45,6 +45,7 @@ struct DeviceState {
>>       QLIST_ENTRY(DeviceState) sibling;
>>       int instance_id_alias;
>>       int alias_required_for_version;
>> +    int no_boot;
>>   };
>>
>>   typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent);
>> diff --git a/net.c b/net.c
>> index 3d0fde7..2370aca 100644
>> --- a/net.c
>> +++ b/net.c
>> @@ -792,6 +792,10 @@ static int net_init_nic(QemuOpts *opts,
>>       if (qemu_opt_get(opts, "addr")) {
>>           nd->devaddr = qemu_strdup(qemu_opt_get(opts, "addr"));
>>       }
>> +    if (qemu_opt_get(opts, "boot")) {
>> +        if (!strcmp("off", qemu_strdup(qemu_opt_get(opts, "boot"))))
>> +            nd->no_boot = 1;
>> +    }
>>
>>       nd->macaddr[0] = 0x52;
>>       nd->macaddr[1] = 0x54;
>> @@ -877,6 +881,10 @@ static const struct {
>>                   .type = QEMU_OPT_STRING,
>>                   .help = "PCI device address",
>>               }, {
>> +                .name = "boot",
>> +                .type = QEMU_OPT_STRING,
>> +                .help = "gPXE boot (on (default), off)",
>> +            }, {
>>                   .name = "vectors",
>>                   .type = QEMU_OPT_NUMBER,
>>                   .help = "number of MSI-x vectors, 0 to disable MSI-X",
>> diff --git a/net.h b/net.h
>> index 518cf9c..288059b 100644
>> --- a/net.h
>> +++ b/net.h
>> @@ -132,6 +132,7 @@ struct NICInfo {
>>       VLANClientState *netdev;
>>       int used;
>>       int nvectors;
>> +    int no_boot;
>>   };
>>
>>   extern int nb_nics;
>> diff --git a/qemu-options.hx b/qemu-options.hx
>> index a0b5ae9..6084aa9 100644
>> --- a/qemu-options.hx
>> +++ b/qemu-options.hx
>> @@ -959,8 +959,10 @@ DEF("smb", HAS_ARG, QEMU_OPTION_smb, "", QEMU_ARCH_ALL)
>>   #endif
>>
>>   DEF("net", HAS_ARG, QEMU_OPTION_net,
>> -    "-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n"
>> +    "-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v][,boot=on|off]\n"
>>       "                create a new Network Interface Card and connect it to VLAN 'n'\n"
>> +    "                use 'boot=on|off' to enable/disable loading of an option rom;\n"
>> +    "                loading enabled is the default\n"
>>   #ifdef CONFIG_SLIRP
>>       "-net user[,vlan=n][,name=str][,net=addr[/mask]][,host=addr][,restrict=y|n]\n"
>>       "         [,hostname=host][,dhcpstart=addr][,dns=addr][,tftp=dir][,bootfile=f]\n"
>> @@ -1014,13 +1016,15 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
>>   #endif
>>       "socket],id=str[,option][,option][,...]\n", QEMU_ARCH_ALL)
>>   STEXI
>> -@item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}]
>> +@item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}][,boot=on|off]
>>   @findex -net
>>   Create a new Network Interface Card and connect it to VLAN @var{n} (@var{n}
>>   = 0 is the default). The NIC is an e1000 by default on the PC
>>   target. Optionally, the MAC address can be changed to @var{mac}, the
>>   device address set to @var{addr} (PCI cards only),
>>   and a @var{name} can be assigned for use in monitor commands.
>> +Optionally, with @option{boot=on|off}, you can enable/disable the loading of an option
>> +rom; by default, loading is enabled.
>>   Optionally, for PCI cards, you can specify the number @var{v} of MSI-X vectors
>>   that the card should have; this option currently only affects virtio cards; set
>>   @var{v} = 0 to disable MSI-X. If no @option{-net} option is specified, a single
>> diff --git a/vl.c b/vl.c
>> index 3f45aa9..2aad6b1 100644
>> --- a/vl.c
>> +++ b/vl.c
>> @@ -2459,6 +2459,33 @@ int main(int argc, char **argv, char **envp)
>>                   if (!qemu_opts_parse(qemu_find_opts("device"), optarg, 1)) {
>>                       exit(1);
>>                   }
>> +
>> +                /* check whether option "boot" is present in the cmd string */
>> +                /* for this a modified string is created that does not */
>> +                /* contain the driver */
>> +                /* if "boot" is present and set to "on", the relevant */
>> +                /* variables are set in a way that net boot is possible and */
>> +                /* that a present "romfile" is loaded for the given device */
>> +                /* note that "default_net" is set to zero in order to avoid */
>> +                /* creation of a default device if option "-net" is not */
>> +                /* present in the complete command line */
>> +                {
>> +                   char  mod_optarg[128];
>> +                   char  *mod_optarg_p;
>> +
>> +                   if ((mod_optarg_p = strchr(optarg, ',')))
>> +                       strcpy(mod_optarg, ++mod_optarg_p);
>> +                   else
>> +                       strcpy(mod_optarg, optarg);
>> +
>> +                   if (get_param_value(mod_optarg, 128, "boot", mod_optarg) != 0) {
>> +                       if (!strcmp("on", mod_optarg)) {
>> +                           char buf[8]="n";
>> +                           pstrcpy(boot_devices, sizeof(boot_devices), buf);
>> +                           default_net = 0;
>> +                       }
>> +                   }
>> +                }
>>                   break;
>>               case QEMU_OPTION_smp:
>>                   smp_parse(optarg);
>> -- 
>> 1.7.2.2
>>
>>      
>
Anthony Liguori Sept. 21, 2010, 3:19 p.m. UTC | #5
On 09/21/2010 09:18 AM, Bernhard Kohl wrote:
> Am 19.09.2010 18:07, schrieb ext Michael S. Tsirkin:
>> On Tue, Sep 14, 2010 at 05:46:55PM +0200, Bernhard Kohl wrote:
>>> >  This patch was motivated by the following use case: In our system
>>> >  the VMs usually have 4 NICs, any combination of virtio-net-pci and
>>> >  pci-assign NIC devices. The VMs boot via gPXE preferably over the
>>> >  pci-assign devices.
>>> > >  There is no way to make this working with a combination of the
>>> >  current options -net -pcidevice -device -optionrom -boot.
>>> > >  With the parameter boot=off it is possible to avoid loading
>>> >  and using gPXE option ROMs either for old style "-net nic" or
>>> >  for "-device" NIC devices. So we can select which NIC is used
>>> >  for booting.
>>> > >  A side effect of the boot=off parameter is that unneeded ROMs
>>> >  which might waste memory are not longer loaded. E.g. if you have
>>> >  2 virtio-net-pci and 2 pci-assign NICs in sum 4 option ROMs are
>>> >  loaded and the virtio ROMs take precedence over the pci-assign
>>> >  ROMs. The BIOS uses the first gPXE ROM which it finds and only
>>> >  needs one of them even if there are more NICs of the same type.
>>> > >  Without using the boot=on|off parameter the current behaviour
>>> >  does not change.
>>> > >  Signed-off-by: Thomas Ostler<thomas.ostler@nsn.com>
>>> >  Signed-off-by: Bernhard Kohl<bernhard.kohl@nsn.com>
>> I think this is useful, however:
>>
>> - We have bit properties which handle parsing on/off
>>    and other formats automatically. Please don't use string.
>> - boot is not a great property name for PCI: what
>>    you actually do is disable option rom.
>>    So maybe call it 'rom' or something like that?
> Our main goal is to select a certain NIC's option rom for booting.
> So the other roms are not needed and not loaded. We used 'boot'
> as the property name as it is similar as in the '-drive' option to
> select a certain disk for booting. What's about to call it 'bootrom'?

This is the wrong approach.  A rom doesn't have to be BEV and if it's 
not BEV or PnP, it may search for any device it can understand.  So even 
if you did boot=on to the third NIC, the first NIC may be booted from.  
So just suppressing ROM loading does not imply that any specific device 
will be chosen to boot from.

The correct approach is to communicate to the BIOS which of the boot 
entries you would like to be chosen by default.  That means QEMU and 
SeaBIOS need to agree on a mechanism to map QEMU visible devices to a 
boot entry.

Regards,

Anthony Liguori
Michael S. Tsirkin Sept. 21, 2010, 3:31 p.m. UTC | #6
On Tue, Sep 21, 2010 at 10:16:29AM -0500, Anthony Liguori wrote:
> On 09/19/2010 11:07 AM, Michael S. Tsirkin wrote:
> >On Tue, Sep 14, 2010 at 05:46:55PM +0200, Bernhard Kohl wrote:
> >>This patch was motivated by the following use case: In our system
> >>the VMs usually have 4 NICs, any combination of virtio-net-pci and
> >>pci-assign NIC devices. The VMs boot via gPXE preferably over the
> >>pci-assign devices.
> >>
> >>There is no way to make this working with a combination of the
> >>current options -net -pcidevice -device -optionrom -boot.
> >>
> >>With the parameter boot=off it is possible to avoid loading
> >>and using gPXE option ROMs either for old style "-net nic" or
> >>for "-device" NIC devices. So we can select which NIC is used
> >>for booting.
> >>
> >>A side effect of the boot=off parameter is that unneeded ROMs
> >>which might waste memory are not longer loaded. E.g. if you have
> >>2 virtio-net-pci and 2 pci-assign NICs in sum 4 option ROMs are
> >>loaded and the virtio ROMs take precedence over the pci-assign
> >>ROMs. The BIOS uses the first gPXE ROM which it finds and only
> >>needs one of them even if there are more NICs of the same type.
> >>
> >>Without using the boot=on|off parameter the current behaviour
> >>does not change.
> >>
> >>Signed-off-by: Thomas Ostler<thomas.ostler@nsn.com>
> >>Signed-off-by: Bernhard Kohl<bernhard.kohl@nsn.com>
> >I think this is useful, however:
> >
> >- We have bit properties which handle parsing on/off
> >   and other formats automatically. Please don't use string.
> 
> This is unneeded.  Just do romfile= with -device and it will
> suppress the option rom loading.
> 
> IOW:
> 
> -device virtio-net-pci,romfile= -pcidevice ...

Cool, but needs to be documented.

> But BTW, you should be able to select the pci device by doing:
> 
> -boot cdn,menu=on
> 
> And then hitting F12.  We need to come up with a better way to let
> particular BEV or BCV devices to be chosen from the command line.
> 
> Regards,
> 
> Anthony Liguori
> 
> >- boot is not a great property name for PCI: what
> >   you actually do is disable option rom.
> >   So maybe call it 'rom' or something like that?
> >- given you have added a property, it can now
> >   be changed with -device. and visible in -device ?
> >   This also has an advantage of only applying to pci devices
> >   (-net option would appear to apply to non-pci but have no effect).
> >   Please do not add more flag parsing in qdemu-options, net and vl.c
> >
> >To summarize, just add a qdev bit option and check
> >the bit.
> >
> >>---
> >>  hw/pci.c        |    8 +++++++-
> >>  hw/pci.h        |    1 +
> >>  hw/qdev.c       |    6 ++++++
> >>  hw/qdev.h       |    1 +
> >>  net.c           |    8 ++++++++
> >>  net.h           |    1 +
> >>  qemu-options.hx |    8 ++++++--
> >>  vl.c            |   27 +++++++++++++++++++++++++++
> >>  8 files changed, 57 insertions(+), 3 deletions(-)
> >>
> >>diff --git a/hw/pci.c b/hw/pci.c
> >>index a98d6f3..055a2be 100644
> >>--- a/hw/pci.c
> >>+++ b/hw/pci.c
> >>@@ -71,6 +71,7 @@ static struct BusInfo pci_bus_info = {
> >>          DEFINE_PROP_UINT32("rombar",  PCIDevice, rom_bar, 1),
> >>          DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
> >>                          QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
> >>+        DEFINE_PROP_STRING("boot", PCIDevice, boot),
> >>          DEFINE_PROP_END_OF_LIST()
> >>      }
> >>  };
> >>@@ -1513,6 +1514,10 @@ PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
> >>
> >>      pci_dev = pci_create(bus, devfn, pci_nic_names[i]);
> >>      dev =&pci_dev->qdev;
> >>+    if (nd->name)
> >>+        dev->id = qemu_strdup(nd->name);
> >>+    if (nd->no_boot)
> >>+        dev->no_boot = 1;
> >>      qdev_set_nic_properties(dev, nd);
> >>      if (qdev_init(dev)<  0)
> >>          return NULL;
> >>@@ -1693,7 +1698,8 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
> >>      /* rom loading */
> >>      if (pci_dev->romfile == NULL&&  info->romfile != NULL)
> >>          pci_dev->romfile = qemu_strdup(info->romfile);
> >>-    pci_add_option_rom(pci_dev);
> >>+    if (!qdev->no_boot)
> >>+        pci_add_option_rom(pci_dev);
> >>
> >>      if (qdev->hotplugged) {
> >>          rc = bus->hotplug(bus->hotplug_qdev, pci_dev, 1);
> >>diff --git a/hw/pci.h b/hw/pci.h
> >>index 1eab7e7..20aa038 100644
> >>--- a/hw/pci.h
> >>+++ b/hw/pci.h
> >>@@ -172,6 +172,7 @@ struct PCIDevice {
> >>      char *romfile;
> >>      ram_addr_t rom_offset;
> >>      uint32_t rom_bar;
> >>+    char *boot;
> >>  };
> >>
> >>  PCIDevice *pci_register_device(PCIBus *bus, const char *name,
> >>diff --git a/hw/qdev.c b/hw/qdev.c
> >>index 35858cb..8445bc9 100644
> >>--- a/hw/qdev.c
> >>+++ b/hw/qdev.c
> >>@@ -249,6 +249,10 @@ DeviceState *qdev_device_add(QemuOpts *opts)
> >>          qdev_free(qdev);
> >>          return NULL;
> >>      }
> >>+    if (qemu_opt_get(opts, "boot")) {
> >>+        if (!strcmp("off", qemu_strdup(qemu_opt_get(opts, "boot"))))
> >>+            qdev->no_boot = 1;
> >>+    }
> >>      if (qdev_init(qdev)<  0) {
> >>          qerror_report(QERR_DEVICE_INIT_FAILED, driver);
> >>          return NULL;
> >>@@ -421,6 +425,8 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
> >>          qdev_prop_exists(dev, "vectors")) {
> >>          qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
> >>      }
> >>+    if (nd->no_boot)
> >>+        qdev_prop_parse(dev, "boot", "off");
> >>  }
> >>
> >>  static int next_block_unit[IF_COUNT];
> >>diff --git a/hw/qdev.h b/hw/qdev.h
> >>index 579328a..e7df371 100644
> >>--- a/hw/qdev.h
> >>+++ b/hw/qdev.h
> >>@@ -45,6 +45,7 @@ struct DeviceState {
> >>      QLIST_ENTRY(DeviceState) sibling;
> >>      int instance_id_alias;
> >>      int alias_required_for_version;
> >>+    int no_boot;
> >>  };
> >>
> >>  typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent);
> >>diff --git a/net.c b/net.c
> >>index 3d0fde7..2370aca 100644
> >>--- a/net.c
> >>+++ b/net.c
> >>@@ -792,6 +792,10 @@ static int net_init_nic(QemuOpts *opts,
> >>      if (qemu_opt_get(opts, "addr")) {
> >>          nd->devaddr = qemu_strdup(qemu_opt_get(opts, "addr"));
> >>      }
> >>+    if (qemu_opt_get(opts, "boot")) {
> >>+        if (!strcmp("off", qemu_strdup(qemu_opt_get(opts, "boot"))))
> >>+            nd->no_boot = 1;
> >>+    }
> >>
> >>      nd->macaddr[0] = 0x52;
> >>      nd->macaddr[1] = 0x54;
> >>@@ -877,6 +881,10 @@ static const struct {
> >>                  .type = QEMU_OPT_STRING,
> >>                  .help = "PCI device address",
> >>              }, {
> >>+                .name = "boot",
> >>+                .type = QEMU_OPT_STRING,
> >>+                .help = "gPXE boot (on (default), off)",
> >>+            }, {
> >>                  .name = "vectors",
> >>                  .type = QEMU_OPT_NUMBER,
> >>                  .help = "number of MSI-x vectors, 0 to disable MSI-X",
> >>diff --git a/net.h b/net.h
> >>index 518cf9c..288059b 100644
> >>--- a/net.h
> >>+++ b/net.h
> >>@@ -132,6 +132,7 @@ struct NICInfo {
> >>      VLANClientState *netdev;
> >>      int used;
> >>      int nvectors;
> >>+    int no_boot;
> >>  };
> >>
> >>  extern int nb_nics;
> >>diff --git a/qemu-options.hx b/qemu-options.hx
> >>index a0b5ae9..6084aa9 100644
> >>--- a/qemu-options.hx
> >>+++ b/qemu-options.hx
> >>@@ -959,8 +959,10 @@ DEF("smb", HAS_ARG, QEMU_OPTION_smb, "", QEMU_ARCH_ALL)
> >>  #endif
> >>
> >>  DEF("net", HAS_ARG, QEMU_OPTION_net,
> >>-    "-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n"
> >>+    "-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v][,boot=on|off]\n"
> >>      "                create a new Network Interface Card and connect it to VLAN 'n'\n"
> >>+    "                use 'boot=on|off' to enable/disable loading of an option rom;\n"
> >>+    "                loading enabled is the default\n"
> >>  #ifdef CONFIG_SLIRP
> >>      "-net user[,vlan=n][,name=str][,net=addr[/mask]][,host=addr][,restrict=y|n]\n"
> >>      "         [,hostname=host][,dhcpstart=addr][,dns=addr][,tftp=dir][,bootfile=f]\n"
> >>@@ -1014,13 +1016,15 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
> >>  #endif
> >>      "socket],id=str[,option][,option][,...]\n", QEMU_ARCH_ALL)
> >>  STEXI
> >>-@item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}]
> >>+@item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}][,boot=on|off]
> >>  @findex -net
> >>  Create a new Network Interface Card and connect it to VLAN @var{n} (@var{n}
> >>  = 0 is the default). The NIC is an e1000 by default on the PC
> >>  target. Optionally, the MAC address can be changed to @var{mac}, the
> >>  device address set to @var{addr} (PCI cards only),
> >>  and a @var{name} can be assigned for use in monitor commands.
> >>+Optionally, with @option{boot=on|off}, you can enable/disable the loading of an option
> >>+rom; by default, loading is enabled.
> >>  Optionally, for PCI cards, you can specify the number @var{v} of MSI-X vectors
> >>  that the card should have; this option currently only affects virtio cards; set
> >>  @var{v} = 0 to disable MSI-X. If no @option{-net} option is specified, a single
> >>diff --git a/vl.c b/vl.c
> >>index 3f45aa9..2aad6b1 100644
> >>--- a/vl.c
> >>+++ b/vl.c
> >>@@ -2459,6 +2459,33 @@ int main(int argc, char **argv, char **envp)
> >>                  if (!qemu_opts_parse(qemu_find_opts("device"), optarg, 1)) {
> >>                      exit(1);
> >>                  }
> >>+
> >>+                /* check whether option "boot" is present in the cmd string */
> >>+                /* for this a modified string is created that does not */
> >>+                /* contain the driver */
> >>+                /* if "boot" is present and set to "on", the relevant */
> >>+                /* variables are set in a way that net boot is possible and */
> >>+                /* that a present "romfile" is loaded for the given device */
> >>+                /* note that "default_net" is set to zero in order to avoid */
> >>+                /* creation of a default device if option "-net" is not */
> >>+                /* present in the complete command line */
> >>+                {
> >>+                   char  mod_optarg[128];
> >>+                   char  *mod_optarg_p;
> >>+
> >>+                   if ((mod_optarg_p = strchr(optarg, ',')))
> >>+                       strcpy(mod_optarg, ++mod_optarg_p);
> >>+                   else
> >>+                       strcpy(mod_optarg, optarg);
> >>+
> >>+                   if (get_param_value(mod_optarg, 128, "boot", mod_optarg) != 0) {
> >>+                       if (!strcmp("on", mod_optarg)) {
> >>+                           char buf[8]="n";
> >>+                           pstrcpy(boot_devices, sizeof(boot_devices), buf);
> >>+                           default_net = 0;
> >>+                       }
> >>+                   }
> >>+                }
> >>                  break;
> >>              case QEMU_OPTION_smp:
> >>                  smp_parse(optarg);
> >>-- 
> >>1.7.2.2
> >>
diff mbox

Patch

diff --git a/hw/pci.c b/hw/pci.c
index a98d6f3..055a2be 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -71,6 +71,7 @@  static struct BusInfo pci_bus_info = {
         DEFINE_PROP_UINT32("rombar",  PCIDevice, rom_bar, 1),
         DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
                         QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
+        DEFINE_PROP_STRING("boot", PCIDevice, boot),
         DEFINE_PROP_END_OF_LIST()
     }
 };
@@ -1513,6 +1514,10 @@  PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
 
     pci_dev = pci_create(bus, devfn, pci_nic_names[i]);
     dev = &pci_dev->qdev;
+    if (nd->name)
+        dev->id = qemu_strdup(nd->name);
+    if (nd->no_boot)
+        dev->no_boot = 1;
     qdev_set_nic_properties(dev, nd);
     if (qdev_init(dev) < 0)
         return NULL;
@@ -1693,7 +1698,8 @@  static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
     /* rom loading */
     if (pci_dev->romfile == NULL && info->romfile != NULL)
         pci_dev->romfile = qemu_strdup(info->romfile);
-    pci_add_option_rom(pci_dev);
+    if (!qdev->no_boot)
+        pci_add_option_rom(pci_dev);
 
     if (qdev->hotplugged) {
         rc = bus->hotplug(bus->hotplug_qdev, pci_dev, 1);
diff --git a/hw/pci.h b/hw/pci.h
index 1eab7e7..20aa038 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -172,6 +172,7 @@  struct PCIDevice {
     char *romfile;
     ram_addr_t rom_offset;
     uint32_t rom_bar;
+    char *boot;
 };
 
 PCIDevice *pci_register_device(PCIBus *bus, const char *name,
diff --git a/hw/qdev.c b/hw/qdev.c
index 35858cb..8445bc9 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -249,6 +249,10 @@  DeviceState *qdev_device_add(QemuOpts *opts)
         qdev_free(qdev);
         return NULL;
     }
+    if (qemu_opt_get(opts, "boot")) {
+        if (!strcmp("off", qemu_strdup(qemu_opt_get(opts, "boot"))))
+            qdev->no_boot = 1;
+    }
     if (qdev_init(qdev) < 0) {
         qerror_report(QERR_DEVICE_INIT_FAILED, driver);
         return NULL;
@@ -421,6 +425,8 @@  void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
         qdev_prop_exists(dev, "vectors")) {
         qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
     }
+    if (nd->no_boot)
+        qdev_prop_parse(dev, "boot", "off");
 }
 
 static int next_block_unit[IF_COUNT];
diff --git a/hw/qdev.h b/hw/qdev.h
index 579328a..e7df371 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -45,6 +45,7 @@  struct DeviceState {
     QLIST_ENTRY(DeviceState) sibling;
     int instance_id_alias;
     int alias_required_for_version;
+    int no_boot;
 };
 
 typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent);
diff --git a/net.c b/net.c
index 3d0fde7..2370aca 100644
--- a/net.c
+++ b/net.c
@@ -792,6 +792,10 @@  static int net_init_nic(QemuOpts *opts,
     if (qemu_opt_get(opts, "addr")) {
         nd->devaddr = qemu_strdup(qemu_opt_get(opts, "addr"));
     }
+    if (qemu_opt_get(opts, "boot")) {
+        if (!strcmp("off", qemu_strdup(qemu_opt_get(opts, "boot"))))
+            nd->no_boot = 1;
+    }
 
     nd->macaddr[0] = 0x52;
     nd->macaddr[1] = 0x54;
@@ -877,6 +881,10 @@  static const struct {
                 .type = QEMU_OPT_STRING,
                 .help = "PCI device address",
             }, {
+                .name = "boot",
+                .type = QEMU_OPT_STRING,
+                .help = "gPXE boot (on (default), off)",
+            }, {
                 .name = "vectors",
                 .type = QEMU_OPT_NUMBER,
                 .help = "number of MSI-x vectors, 0 to disable MSI-X",
diff --git a/net.h b/net.h
index 518cf9c..288059b 100644
--- a/net.h
+++ b/net.h
@@ -132,6 +132,7 @@  struct NICInfo {
     VLANClientState *netdev;
     int used;
     int nvectors;
+    int no_boot;
 };
 
 extern int nb_nics;
diff --git a/qemu-options.hx b/qemu-options.hx
index a0b5ae9..6084aa9 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -959,8 +959,10 @@  DEF("smb", HAS_ARG, QEMU_OPTION_smb, "", QEMU_ARCH_ALL)
 #endif
 
 DEF("net", HAS_ARG, QEMU_OPTION_net,
-    "-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n"
+    "-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v][,boot=on|off]\n"
     "                create a new Network Interface Card and connect it to VLAN 'n'\n"
+    "                use 'boot=on|off' to enable/disable loading of an option rom;\n"
+    "                loading enabled is the default\n"
 #ifdef CONFIG_SLIRP
     "-net user[,vlan=n][,name=str][,net=addr[/mask]][,host=addr][,restrict=y|n]\n"
     "         [,hostname=host][,dhcpstart=addr][,dns=addr][,tftp=dir][,bootfile=f]\n"
@@ -1014,13 +1016,15 @@  DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
 #endif
     "socket],id=str[,option][,option][,...]\n", QEMU_ARCH_ALL)
 STEXI
-@item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}]
+@item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}][,boot=on|off]
 @findex -net
 Create a new Network Interface Card and connect it to VLAN @var{n} (@var{n}
 = 0 is the default). The NIC is an e1000 by default on the PC
 target. Optionally, the MAC address can be changed to @var{mac}, the
 device address set to @var{addr} (PCI cards only),
 and a @var{name} can be assigned for use in monitor commands.
+Optionally, with @option{boot=on|off}, you can enable/disable the loading of an option
+rom; by default, loading is enabled.
 Optionally, for PCI cards, you can specify the number @var{v} of MSI-X vectors
 that the card should have; this option currently only affects virtio cards; set
 @var{v} = 0 to disable MSI-X. If no @option{-net} option is specified, a single
diff --git a/vl.c b/vl.c
index 3f45aa9..2aad6b1 100644
--- a/vl.c
+++ b/vl.c
@@ -2459,6 +2459,33 @@  int main(int argc, char **argv, char **envp)
                 if (!qemu_opts_parse(qemu_find_opts("device"), optarg, 1)) {
                     exit(1);
                 }
+
+                /* check whether option "boot" is present in the cmd string */
+                /* for this a modified string is created that does not */
+                /* contain the driver */
+                /* if "boot" is present and set to "on", the relevant */
+                /* variables are set in a way that net boot is possible and */
+                /* that a present "romfile" is loaded for the given device */
+                /* note that "default_net" is set to zero in order to avoid */
+                /* creation of a default device if option "-net" is not */
+                /* present in the complete command line */
+                {
+                   char  mod_optarg[128];
+                   char  *mod_optarg_p;
+
+                   if ((mod_optarg_p = strchr(optarg, ',')))
+                       strcpy(mod_optarg, ++mod_optarg_p);
+                   else
+                       strcpy(mod_optarg, optarg);
+
+                   if (get_param_value(mod_optarg, 128, "boot", mod_optarg) != 0) {
+                       if (!strcmp("on", mod_optarg)) {
+                           char buf[8]="n";
+                           pstrcpy(boot_devices, sizeof(boot_devices), buf);
+                           default_net = 0;
+                       }
+                   }
+                }
                 break;
             case QEMU_OPTION_smp:
                 smp_parse(optarg);